package com.mach.platform.service;

import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.google.common.base.Splitter;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Ordering;
import com.mach.platform.constants.CommonConstants;
import com.mach.platform.domain.DevFollow;
import com.mach.platform.domain.EnergyStruc;
import com.mach.platform.domain.IotDevImportModel;
import com.mach.platform.domain.iot.*;
import com.mach.platform.innotation.DevCache;
import com.mach.platform.innotation.DevToCache;
import com.mach.platform.mapper.DevMapper;
import com.mach.platform.repository.*;
import com.mach.platform.service.js.iot.IOTJsService;
import com.mach.platform.util.SqlHelper;
import com.mach.platform.utils.*;
import com.mach.platform.utils.security.SecurityUtils;
import com.mach.platform.utils.springdata.Collections3;
import com.mach.platform.utils.springdata.DynamicSpecifications;
import com.mach.platform.utils.springdata.SearchFilter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.hibernate.query.internal.NativeQueryImpl;
import org.hibernate.transform.Transformers;
import org.joda.time.DateTime;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import javax.sql.DataSource;
import javax.transaction.Transactional;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.net.InetAddress;
import java.sql.SQLException;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.text.ParseException;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @author Anonymous
 * @Description: 设备库 服务类
 * @Package: com.mach.platform.service
 * @time 2018/04/27 23:11
 */
@Slf4j
@Service
public class IotDevServiceImpl implements BaseService<IotDev> {

	private SqlHelper sqlHelper = null;

	@Autowired
	private IotDevRepo deviceRepo;

	@Autowired
	private DevFollowRepo devFollowRepo;

	@Autowired
	private IotDevRepo iotDevRepo;

	@Autowired
	private IotSpaceRepo iotSpaceRepo;

	@Autowired
	private DataSource dataSource;

	@Autowired
	private ConfigDeviceRepo configDeviceRepo;

	@Value("${victure}")
	private String victures;

	@Resource
	private DevMapper devMapper;

	@Autowired
    private IotSpaceServiceImpl spaceService;

	@Autowired
	private EnergyStrucRepo energyStrucRepo;

	@Autowired
	private IOTJsService iotJsService;

	@Autowired
	private IotCollItemRepo collItemRepo;

	@Autowired
	private IotDevParamsRepo paramsRepo;

	@Autowired
	private AlarmServiceForeignImpl alarmForeignService;

	@Autowired
	private IotDevParamsRepo devParamsRepo;

	@Autowired
	private AlarmServiceImpl alarmService;

	@Autowired
	private CacheServiceImpl cacheService;

	/**
	 * 郑州，花都1，花都2，襄阳，大连工厂的产量表的设备id
	 */
	private static String yieldDevIds = "278,11024,11129,11165,11201";

    /*
		@PersistenceContext
		注入的是实体管理器，执行持久化操作的，需要配置文件persistence.xml。
		注入一堆保存实体类状态的数据结构，针对实体类的不同状态(四种,managedh或detached等)可以做出不同的反应(merge,persist等等)，
		其实就是把数据从数据库里提出，然后在内存里处理的，再返回数据库的法则。

		@Resource
		是注入容器提供的资源对象，比如SessionContext MessageDrivenContext。或者你那个name指定的JNDI对象
		可以理解为资源->数据源->也就是数据连接，基本上就是告诉程序数据库在哪里
     */
	@PersistenceContext
	private EntityManager em;


	public Map getMap(Integer[] devIds1, Integer[] devIds2) {
		Map map = new HashMap();
		for (int i = 0; i < devIds1.length; i++) {
			map.put(devIds1[i], devIds2[i]);
		}
		return map;
	}


	/**
	 * 根据i获取工厂简称
	 * @param i
	 * @return
	 */
//	public String getFactory(int i) {
//		if (i < 5) {
//			return "DL";
//		}
//		if (i >= 5 && i < 10) {
//			return "XY";
//		}
//		if (i >= 10 && i < 15) {
//			return "HD2";
//		}
//		if (i >= 15 && i < 20) {
//			return "HD1";
//		}
//		return "ZZ";
//	}


	/**
	 * 临时插入车间数据
	 */
	@Transactional(rollbackOn = Exception.class)
	public List<String> insert2019AfterWorkData() {
		String dataType = "成本";
		String carbonCost = "cost";
		/**
		 * 车间碳排或者成本表设备id
		 */
		Integer[] devIds = {11197,11161,11125,11047};
		/**
		 * 车间电表设备id
		 */
		Integer[] eleDevIds = {11198,11162,11126,11021};
		/**
		 * 车间燃气表设备id
		 */
		Integer[] gasDevIds = {11200,11164,11128,11023};
		String[] factorys = {"DL", "XY", "HD2", "HD1"}; // 所有工厂

		Map carbonCostEleMap = getMap(devIds, eleDevIds);
		Map eleGasMap = getMap(eleDevIds, gasDevIds);

		// 查询win表电和燃气数据
		List<Map> eleData = iotDevRepo.eleData(Arrays.asList(eleDevIds));
		List<Map> gasData = iotDevRepo.gasData(Arrays.asList(gasDevIds));
		List<String> result = new ArrayList<>();
		int number = 0;
		// 开始计算数据
		long start = System.currentTimeMillis();
		String sql = "replace into iot_dev_data_win (dev_id, order_num, the_time, data_type, dvalue) values";
		for (int i = 0; i < devIds.length; i++) {
			for (Map eleMap : eleData) {
				Integer eleDevId = (Integer) eleMap.get("dev_id");
				String eleTime = (String) eleMap.get("the_time");
				double eleValue = (double) eleMap.get("dvalue");
				if (carbonCostEleMap.get(devIds[i]).equals(eleDevId)) {
					double gasValue = 0;
					for (Map gasMap : gasData) {
						Integer gasDevId = (Integer) gasMap.get("dev_id");
						String gasTime = (String) gasMap.get("the_time");
						Integer eleGasDevId = (Integer) eleGasMap.get(eleDevId);
						if (null != eleGasDevId && eleGasDevId.equals(gasDevId) && eleTime.equals(gasTime)) {
							gasValue = (double) gasMap.get("dvalue");
							break;
						}
					}
					String year = eleTime.substring(0, 4);
					String factory = factorys[i];
					String eleKey = carbonCost + factory + year + "ele";
					String gasKey = carbonCost + factory + year + "gas";
					double eleModulus = (double) CommonConstants.modulus.get(eleKey);
					double gasModulus = (double) CommonConstants.modulus.get(gasKey);
					double value = (eleValue * eleModulus + gasValue * gasModulus);
					value = UServ.retainDecimal(value, "0000");
//					System.out.println("dev_id："+devIds[i]+", the_time："+eleTime+", data_type："+dataType+", value "+value);
					sql += " ("+devIds[i]+", 1, '"+eleTime+"', '"+dataType+"', "+value+"),";
					number++;
				}
			}
		}
		sql = sql.substring(0, sql.length() - 1);
		SqlHelper sqlHelper = getSqlHelper();
		try {
			sqlHelper.update(sql);
		} catch (SQLException e) {
			e.printStackTrace();
		}
		long end = System.currentTimeMillis();
		System.out.println("总时间：" + (end - start) + "毫秒");
		System.out.println("总数据：" + number);
		return result;
	}


	/**
	 * 临时插入工厂数据
	 */
//	@Transactional(rollbackOn = Exception.class)
//	public List<String> insert2019AfterFactoryData(String dataType, Integer[] devIds, String carbonCost) {
//		String[] factorys = {"DL", "XY", "HD2", "HD1", "ZZ"}; // 所有工厂
//		// 查询2019之前电数据
//		Integer[] eleDevIds = {11168, 11132, 11085, 11006, 285}; // 工厂电表设备id
//		Integer[] gasDevIds = {11170, 11134, 11089, 11008, 292}; // 工厂燃气表设备id
//
//		Map costEleMap = getMap(devIds, eleDevIds);
//		Map eleGasMap = getMap(eleDevIds, gasDevIds);
//
//		// 查询win表电和燃气数据
//		List<Map> eleData = iotDevRepo.eleData(Arrays.asList(eleDevIds));
//		List<Map> gasData = iotDevRepo.gasData(Arrays.asList(gasDevIds));
//		List<String> result = new ArrayList<>();
//		int number = 1;
//		// 开始计算数据
//		for (int i = 0; i < devIds.length; i++) {
//			for (Map eleMap : eleData) {
//				Integer eleDevId = (Integer) eleMap.get("dev_id");
//				String eleTime = (String) eleMap.get("the_time");
//				double eleValue = (double) eleMap.get("dvalue");
//				if (costEleMap.get(devIds[i]).equals(eleDevId)) {
//					for (Map gasMap : gasData) {
//						Integer gasDevId = (Integer) gasMap.get("dev_id");
//						String gasTime = (String) gasMap.get("the_time");
//						double gasValue = (double) gasMap.get("dvalue");
//						if (eleGasMap.get(eleDevId).equals(gasDevId) && eleTime.equals(gasTime)) {
//							String year = eleTime.substring(0, 4);
//							String eleKey = carbonCost + factorys[i] + year + "ele";
//							String gasKey = carbonCost + factorys[i] + year + "gas";
//							double eleModulus = (double) CommonConstants.modulus.get(eleKey);
//							double gasModulus = (double) CommonConstants.modulus.get(gasKey);
//							double value = (eleValue * eleModulus + gasValue * gasModulus);
//							value = UServ.retainDecimal(value, "0000");
//							int count = iotDevRepo.insertWinData(devIds[i], 1, eleTime, dataType, value);
//							if (count == 1) {
//								System.out.println("插入成功第" + number + "条...");
//							} else {
//								System.out.println("插入失败...");
//							}
//							number++;
//							break;
//						}
//					}
//				}
//			}
//		}
//		return result;
//	}


	/**
	 * 获取数据库连接
	 * @return
	 */
	public SqlHelper getSqlHelper() {
		if (null == sqlHelper) {
			SqlHelper newSqlHelper = SqlHelper.getBySource(dataSource);
			sqlHelper = newSqlHelper;
			return newSqlHelper;
		}
		return sqlHelper;
	}


	/**
	 * 查询车间所有设备的报警状态(有一个异常，就报警)
	 * @return
	 */
	public int workShopAlarmStatus() {
		return alarmForeignService.isAlarm;
	}


	/**
	 * 保存
	 *
	 * @param device 保存的实体
	 * @return T 返回保存后的实体
	 */
	@Transactional(rollbackOn = Exception.class)
	@DevToCache
	@Override
	public IotDev save (IotDev device) {
		// 如果非真实，虚拟设备，数据库iot_dev表的dev_type_id字段值默认为1，对应设备为：虚拟设备类型，否则查询数据有问题
		int type = device.getType();
		if (type > 1) {
			IotDevType devType = new IotDevType();
			long id = 1;
			devType.setId(id);
			device.setIotDevType(devType);
		}
		if (type == 0) {
			saveBusDeviceParams(device);
		}
		IotDev dbResult = deviceRepo.saveAndFlush(device);
		if (null == device.getSort()) {
			dbResult.setSort(dbResult.getId().floatValue()); // 默认的排序值是id
			dbResult = deviceRepo.saveAndFlush(dbResult);
		}
		return dbResult;
	}


    /**
     * 如果是母排测温下面的设备，参数设定那里自动生成默认温度设定参数
     * @param iotDev 设备
     */
	public void saveBusDeviceParams(IotDev iotDev) {
        Long spaceId = iotDev.getIotSpace().getId();
        IotSpace iotSpace = iotSpaceRepo.findUpperLevel(spaceId);
        Integer type = null;
        if (null != iotSpace && null != iotSpace.getType()) {
            type = iotSpace.getType();
        }
        if (null != type && type == 12) {
			String[] labels = {"母线编号", "开关编号", "负载范围", "A相温度上限", "A相温度下限", "A时间范围", "A温差上涨", "B相温度上限", "B相温度下限", "B时间范围", "B温差上涨", "C相温度上限", "C相温度下限", "C时间范围", "C温差上涨", "温差幅度"};
			String[] names = {"busNumber", "switchNumber", "loadRange", "aUpperLimit", "aLowerLimit", "aTimeLimit", "aTemperRise", "bUpperLimit", "bLowerLimit", "bTimeLimit", "bTemperRise", "cUpperLimit", "cLowerLimit", "cTimeLimit", "cTemperRise", "temperDiffer"};
            double[] values = {0.0, 0.0, 0.0, 50.0, 10.0, 20.0, 10.0, 50.0, 10.0, 20.0, 10.0, 50.0, 10.0, 20.0, 10.0, 12.0}; // 默认参数值
            List<IotDevParams> devParamsList = new ArrayList<>();
            IotDevParams devParams;
            for (int i = 0; i < labels.length; i++) {
                devParams = new IotDevParams();
                devParams.setName(names[i]);
                devParams.setLabel(labels[i]);
                devParams.setValue(values[i]);
                devParamsList.add(devParams);
            }
            iotDev.setDevParams(devParamsList);
        }
    }


	/**
	 * 加载母线设备的实时数据
	 * @param id 设备id
	 * @return
	 */
    public Map loadIotDevCurData(Long id) {
    	// 设备属性和负载范围数据放在缓存里面
		String itemsKey = id + "items";
		String loadKey = id + "loadRange";
		List<String> items = (List<String>) cacheService.getCache(itemsKey);
		String loadRange = (String) cacheService.getCache(loadKey);
		if (Collections3.isEmpty(items)) {
			items = collItemRepo.findIotDevItems(id);
			cacheService.putCache(itemsKey, items);
		}
		if (null == loadRange) {
			loadRange = devParamsRepo.findLoadRangeByDevId(id.intValue()).getTextValue();
			cacheService.putCache(loadKey, null == loadRange ? "" : loadRange);
		}
		List<Map> curData = iotDevRepo.devItemsCurData(id);
		Map resultMap = new HashMap(); // 返回结果
		List<Map> itemList = new ArrayList<>(); // 属性数据List
		Map loadMap = new HashMap(); // 负载范围Map
		loadMap.put("value", loadRange);
		loadMap.put("status", 1);
		itemList.add(loadMap);
		Map alarmResult = alarmForeignService.getItemStatusByDevId(id.intValue());
		// 组装设备母线设备的实时数据Map
		for (String item : items) {
			Object value = "-";
			String unit = "";
			for (Map dataMap : curData) {
				if (item.equals(dataMap.get("data_type"))) {
					value = dataMap.get("dvalue");
					unit = (String) dataMap.get("unit");
					break;
				}
			}
			Map map = new HashMap();
			map.put("value", value + unit);
			map.put("status", 1); // 运行状态 0.异常 1.正常
			// 判断设备的属性数据是否异常
			for (Object key : alarmResult.keySet()) {
				if (item.equals(key) && (int) alarmResult.get(key) != 0) {
					map.put("status", 0); // 不等于0，异常
					break;
				}
			}
			itemList.add(map);
		}
		// 判断设备是否异常
		int status = 1; // 默认是正常
		for (Object key : alarmResult.keySet()) {
			if ((int) alarmResult.get(key) != 0) {
				status = 0; // 异常
				break;
			}
		}
		resultMap.put("id", id);
		resultMap.put("status", status);
		resultMap.put("itemData", itemList);
		return resultMap;
	}

	/**
	 * 母排测温温度走势
	 * @param id 设备id
	 * @param startTime 开始时间
	 * @param endTime 结束时间
	 * @return
	 */
	public Map temperatureTrend(Long id, String startTime, String endTime) {
		// 从缓存读取设备的属性数据
		String itemKey = id + "items";
		List<String> items = (List<String>) cacheService.getCache(itemKey);
		if (Collections3.isEmpty(items)) {
			items = collItemRepo.findIotDevItems(id);
			cacheService.putCache(itemKey, items);
		}
		String lastTime = DateUtil.getDaysBeforeAfter(endTime, "+", 1);
		List<Map> resultData;
		if (startTime.equals(endTime)) {
			resultData = iotDevRepo.temperMinuteTrend(id, startTime, lastTime);
		} else {
			resultData = iotDevRepo.temperHourTrend(id, startTime, lastTime);
		}
		// 确定时间结果集大小,按时间分
		Set<String> times = new TreeSet<>();
		Map<Object,Object> aMap = new HashMap<>();
		Map<Object,Object> bMap = new HashMap<>();
		Map<Object,Object> cMap = new HashMap<>();
		for (Map map : resultData) {
			Object dataType = map.get("data_type");
			Object theTime = map.get("time");
			Object value = map.get("dvalue");
			times.add((String) theTime);
			if(dataType.equals(items.get(0))){
				aMap.put(theTime, value);
			}else if(dataType.equals(items.get(1))){
				bMap.put(theTime, value);
			}else if(dataType.equals(items.get(2))){
				cMap.put(theTime, value);
			}
		}
        // 遍历时间结果集填充数据
		Iterator<String> it = times.iterator();
		List<Map> aList = new ArrayList<>();
		List<Map> bList = new ArrayList<>();
		List<Map> cList = new ArrayList<>();
		while(it.hasNext()){
			String time = it.next();
			Map aItemMap = Maps.newHashMap();
			Map bItemMap = Maps.newHashMap();
			Map cItemMap = Maps.newHashMap();
			Object[] dataA = new Object[2];
			Object[] dataB = new Object[2];
			Object[] dataC = new Object[2];
			dataA[0] = time;
			dataB[0] = time;
			dataC[0] = time;
			String aValue = "-";
			String bValue = "-";
			String cValue = "-";
			if (aMap.containsKey(time)) {
				aValue = aMap.get(time).toString();
			}
			if (bMap.containsKey(time)) {
				bValue = bMap.get(time).toString();
			}
			if (cMap.containsKey(time)) {
				cValue = cMap.get(time).toString();
			}
			dataA[1] = aValue;
			dataB[1] = bValue;
			dataC[1] = cValue;
			aItemMap.put("name", time);
			aItemMap.put("value", dataA);
			bItemMap.put("name", time);
			bItemMap.put("value", dataB);
			cItemMap.put("name", time);
			cItemMap.put("value", dataC);
			aList.add(aItemMap);
			bList.add(bItemMap);
			cList.add(cItemMap);
		}
		List<List<Map>> resultList = new ArrayList<>();
		resultList.add(aList);
		resultList.add(bList);
		resultList.add(cList);
		List<Map> series = new ArrayList<>();
		for (int i = 0; i < items.size(); i++) {
			Map dataMap = Maps.newHashMap();
			dataMap.put("name", items.get(i));
			dataMap.put("data", resultList.get(i));
			series.add(dataMap);
		}
		Map result = new HashMap();
		result.put("legend", items);
		result.put("series", series);
		return result;
	}


	/**
	 * 下载母线设备曲线走势数据
	 * @param id 设备id
	 */
	public XSSFWorkbook downBusDevData(Long id, String startTime, String endTime) {
        // 从缓存读取设备的属性数据
        String itemKey = id + "items";
        List<String> items = (List<String>) cacheService.getCache(itemKey);
        if (Collections3.isEmpty(items)) {
            items = collItemRepo.findIotDevItems(id);
            cacheService.putCache(itemKey, items);
        }
		String lastTime = DateUtil.getDaysBeforeAfter(endTime, "+", 1);
		List<Map> resultData = iotDevRepo.temperMinuteTrend(id, startTime, lastTime);
		XSSFWorkbook workbook = new XSSFWorkbook();
		Sheet sheet = workbook.createSheet("设备属性数据");
		if (Collections3.isEmpty(resultData)) {
			return workbook;
		}
		Row row = sheet.createRow(0);
		// 组装表头数据
		for (int i = 0; i < items.size(); i++) {
			Cell cell = row.createCell(i + 1);
			cell.setCellValue(items.get(i));
		}
		List<String> times = new ArrayList<>();
		List<String> timeList = Collections3.extractToList(resultData, "time");
		// 获取resultData里面不重复的时间
		for (String time : timeList) {
			if (!times.contains(time)) {
				times.add(time);
			}
		}
		// 开始组装Excel表的所有数据
		for (int i = 0; i < times.size(); i++) {
			String time = times.get(i);
			// 得到当前行数的下一行
			row = sheet.createRow(row.getRowNum() + 1);
			for (int j = 0; j <= items.size(); j++) {
				if (j == 0) {
					row.createCell(j).setCellValue(time);
				} else {
					Double value = null;
					for (Map map : resultData) {
						String dTime = (String) map.get("time");
						String item = (String) map.get("data_type");
						if (time.equals(dTime) && items.get(j - 1).equals(item)) {
							value = (Double) map.get("dvalue");
							break;
						}
					}
					if (null != value) {
						row.createCell(j).setCellValue(value);
					}
				}
			}
		}
		return workbook;
	}


	/**
	 * 查询母线报警温度参数数据
	 * @param id 设备id
	 * @return
	 */
	public Map alarmParams(Long id) {
		List<Map> devParams = paramsRepo.findByDevId(id);
		Map result = new HashMap();
		for (Map map : devParams) {
			Double value = (Double) map.get("value");
			String valueStr = String.valueOf(value);
			if (valueStr.contains(".") && valueStr.endsWith("0")) {
				valueStr = valueStr.split("\\.")[0];
			}
			result.put(map.get("name"), valueStr);
		}
		return result;
	}


	/**
	 * 母线报警温度设置
	 * @param params 设置参数，包括设备id
	 * @return
	 */
	public boolean alarmSystem(Map params) {
		SqlHelper sqlHelper = getSqlHelper();
		Integer devId = (Integer) params.get("id");
		String sql = "update iot_dev_prop set value = case name" +
				" when 'aUpperLimit' then " + params.get("aUpperLimit") +
				" when 'aLowerLimit' then " + params.get("aLowerLimit") +
				" when 'aTimeLimit' then " + params.get("aTimeLimit") +
				" when 'aTemperRise' then " + params.get("aTemperRise") +
				" when 'bUpperLimit' then " + params.get("bUpperLimit") +
				" when 'bLowerLimit' then " + params.get("bLowerLimit") +
				" when 'bTimeLimit' then " + params.get("bTimeLimit") +
				" when 'bTemperRise' then " + params.get("bTemperRise") +
				" when 'cUpperLimit' then " + params.get("cUpperLimit") +
				" when 'cLowerLimit' then " + params.get("cLowerLimit") +
				" when 'cTimeLimit' then " + params.get("cTimeLimit") +
				" when 'cTemperRise' then " + params.get("cTemperRise") +
				" when 'temperDiffer' then " + params.get("temperDiffer") +
				" when 'loadRange' then 0" +
				" when 'busNumber' then 0" +
				" when 'switchNumber' then 0" +
				" end where dev_id = " + devId;
		try {
			sqlHelper.update(sql);
			// 修改参数设定，清除对应的缓存
			cacheService.removeCache(devId + "params");
			return true;
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return false;
	}


	/**
	 * 通过设备名称/编号查询设备
	 * @param nameSn 设备名称/设备编号
	 * @return
	 */
	public Map findByNameNumber(String nameSn) {
		return iotDevRepo.findByNameSn(nameSn);
	}


	/**
	 * 计算两个时间相差的分钟数
	 * @param endDate 结束时间
	 * @param startDate 开始时间
	 * @return
	 */
	public long getDatePoor(Date endDate, Date startDate) {
		long nd = 1000 * 60 * 60 * 24;
		long nh = 1000 * 60 * 60;
		long nm = 1000 * 60;
		// 获得两个时间的毫秒时间差异
		long diff = endDate.getTime() - startDate.getTime();
		// 计算差多少分钟
		long minute = diff % nd % nh / nm;
		return minute;
	}


	/**
	 * 判断系统是否正常(查询cur表一小时内的全部母线设备属性数据，有数据则代表系统-采集器是正常的，否则异常)
	 * @return
	 */
	public boolean systemDiagnosis() {
		// 1. 查询母排测温下面的所有设备id
		List<Integer> devIds = deviceRepo.findBusbarAllDevIds(alarmService.spaceId);
		// 2. 查询所有母线设备的实时数据
		List<Map> curDataList = iotDevRepo.curDataByDevIds(devIds);
		if (Collections3.isEmpty(curDataList)) {
            return false;
        }
		return true;
	}


	/**
	 * 网络诊断(是否可以ping通路由IP地址)
	 * @param nameSn 设备名称/设备编号
	 * @return
	 */
	public boolean networkDiagnosis(String nameSn) {
		Map iotDev = iotDevRepo.findByNameSn(nameSn);
		String commAddr = (String) iotDev.get("comm_addr");
		String host = commAddr.split(":")[0];
		boolean flag = false;
		try {
			// 设置超时时间为3秒
			flag = InetAddress.getByName(host).isReachable(3000);
		} catch (IOException e) {
			e.printStackTrace();
		}
		return flag;
	}


	/**
	 * 诊断设备在线情况(查询cur表的数据是否在半个小时之内)
	 * @param nameSn 设备名称/设备编号
	 * @return
	 */
	public boolean onlineDiagnosis(String nameSn) {
		Map iotDev = iotDevRepo.findByNameSn(nameSn);
		Integer devId = (Integer) iotDev.get("id");
		List<Map> curData = iotDevRepo.devItemsCurData(devId.longValue());
		Date nowDate = new Date();
		for (Map map : curData) {
			Date date = (Date) map.get("uptime");
			long minute = getDatePoor(nowDate, date);
			if (minute < 30) {
				return true;
			}
		}
		return false;
	}


	/**
	 * 查询设备所有属性数据是否异常
	 * @param nameSn 设备名称/编号
     * @return
	 */
	public List<Map> allDataDiagnosis(String nameSn) {
        Map iotDev = iotDevRepo.findByNameSn(nameSn);
		Integer devId = (Integer) iotDev.get("id");
        Map alarmResult = alarmForeignService.getItemStatusByDevId(devId);
		List<Map> resultList = new ArrayList<>();
		List<String> items = collItemRepo.findIotDevItems(devId.longValue());
		List<Map> curData = iotDevRepo.devItemsCurData(devId.longValue());
		for (String prop : items) {
			int status = 0; // 默认是异常
			for (Object key : alarmResult.keySet()) {
				if (prop.equals(key) && (int) alarmResult.get(key) == 0) {
					status = 1;
					break;
				}
			}
			Object data = "-";
			String unit = "";
			for (Map map : curData) {
				if (prop.equals(map.get("data_type"))) {
					data = map.get("dvalue");
					unit = (String) map.get("unit");
					break;
				}
			}
			Map map = new HashMap();
			map.put("name", prop);
			map.put("status", status);
			map.put("data", data + unit);
			resultList.add(map);
		}
		return resultList;
	}


	/**
	 * 查询设备某个属性数据是否异常
	 * @param nameSn 设备名称/编号
	 * @param item 查询属性
	 * @return
	 */
	public List<Map> oneDataDiagnosis(String nameSn, String item) {
		Map iotDev = iotDevRepo.findByNameSn(nameSn);
		Integer devId = (Integer) iotDev.get("id");
		Map alarmResult = alarmForeignService.getItemStatusByDevId(devId);
		Map curData = iotDevRepo.findByDevIdDataType(devId.longValue(), item);
		int status = 0; // 默认是异常
		for(Object key : alarmResult.keySet()) {
			if (item.equals(key) && (int) alarmResult.get(key) == 0) {
				status = 1;
				break;
			}
		}
		List<Map> result = new ArrayList<>();
		Map map = new HashMap();
		String unit = (String) curData.get("unit");
		map.put("name", item);
		map.put("status", status);
		map.put("data", curData.get("dvalue") + unit);
		result.add(map);
		return result;
	}


	/**
	 * 新版同类对比接口，因为逻辑比较复杂，调试很复杂，暂时先把js代码写到后台
	 * @param type 能源名称
	 * @param workSpaceName 空间名称
	 * @param time 时间
	 * @param selectType total：用量数据 single：单车数据
	 * @return
	 */
	public List<Map> similarContrast(String type, String workSpaceName, String time, String selectType) {
		String workSpaceNames = getWorkSpaceNames(workSpaceName);
		SqlHelper sqlHelper = getSqlHelper();
		String strucIds = iotJsService.getEnergyStrucIdsByNameType(workSpaceNames, type);
		String formatTime = dateFormatTime(time);
		String ringTime = UServ.getRingTime(time);
		int espType = 1; // 默认计量属性
		if (type.equals("碳排") || type.equals("成本")) {
			espType = 2;
		}
		String totalSql = "select esp.energy_struc_id targetId, DATE_FORMAT(win.the_time,'" + formatTime + "') time, sum(win.dvalue) data" +
				" from iot_dev_data_win win inner join energy_struc_prop esp on win.dev_id = esp.dev_id and win.data_type = esp.name" +
				" inner join energy_struc es on es.id = esp.energy_struc_id" +
				" where es.type = '" + type + "' and esp.type = " + espType + " and esp.field_type = '用量' and esp.energy_struc_id in (" + strucIds + ")" +
				" and (win.the_time like '" + time + "%' or win.the_time like '" + ringTime + "%') group by targetId, time";
		String yieldSql = "select dev_id, DATE_FORMAT(the_time,'" + formatTime + "') time, sum(dvalue) data from iot_dev_data_win" +
				" where dev_id in (" + yieldDevIds + ") and (the_time like '" + time + "%' or the_time like '" + ringTime + "%') group by dev_id, time";
		List<Map<String,Object>> resultData = null;
		List<Map<String, Object>> yieldData = null;
		List<String> times = new ArrayList<>();
		times.add(ringTime);
		times.add(time);
		try {
			resultData = sqlHelper.queryList(totalSql);
//			if (selectType.equals("single")) {
				yieldData = sqlHelper.queryList(yieldSql);
				yieldData = getYieldResult(times, yieldData);
//			}
		} catch (SQLException e) {
			e.printStackTrace();
		}
		Long[] targetIdArr = stringToLongArr(strucIds);
		resultData = getTotalResult(targetIdArr, times, resultData);
		List<Map> result = totalSingleRingData(workSpaceName, selectType, type, targetIdArr, resultData, yieldData);
		if (Objects.equals("PV", workSpaceName)) {
			List<Map> singleRingData = totalSingleRingData(workSpaceName, "single", type, targetIdArr, resultData, yieldData);
			result = getSingleData(result, singleRingData);
		}
		return result;
	}

	private List<Map> getSingleData(List<Map> result, List<Map> singleRingData) {
		if (CollectionUtils.isNotEmpty(result) && CollectionUtils.isNotEmpty(singleRingData)){
			for (int index = 0; index < singleRingData.size(); index ++){
				result.get(index).put("singleIncrease", singleRingData.get(index).get("increase"));
				result.get(index).put("singleUseNum", singleRingData.get(index).get("useNum"));
			}
		}
		return result;
	}


	/**
     * 通过空间名字获取所有的同类空间名字
     * @param workSpaceName 空间名字
     * @return
     */
    public String getWorkSpaceNames(String workSpaceName) {
        List<EnergyStruc> energyStrucs = energyStrucRepo.findAllByType("模板");
        Set<String> factorys = new HashSet<>();
        for (EnergyStruc struc : energyStrucs) {
            String name = struc.getName();
            if (struc.getLevel() == 1) {
                factorys.add("PV/" + name);
            }
        }
        String[] workSpaceNames = workSpaceName.split("/");
        if (workSpaceNames.length == 1 || workSpaceNames.length == 2) { // 获取所有工厂的空间名称
            return Collections3.convertToString(factorys, ",");
        }
        Set<String> workShops = new HashSet<>();
        for (String factory : factorys) { // 获取所有车间的空间名称
            workShops.add(factory + "/" + workSpaceNames[2]);
        }
        return Collections3.convertToString(workShops, ",");
    }


	/**
	 * 同类对比每一个架构的当前数据和环比数据的集合
	 * @param targetId 架构id
	 * @param selectType 用量还是单车
	 * @param strucIdFactory 架构id和factory的对应关系
	 * @param totalData 用量数据
	 * @param yieldData 产量数据
	 * @return
	 */
    public List<Double> totalSingleData(Long targetId, String selectType, Map strucIdFactory, List<Map<String, Object>> totalData, List<Map<String, Object>> yieldData) {
		List<Double> datas = new ArrayList<>();
		for (Map totalMap : totalData) {
			String factory1 = (String) strucIdFactory.get(totalMap.get("targetId"));
			String time1 = (String) totalMap.get("time");
			if (targetId.equals(totalMap.get("targetId"))) {
				double data = Double.parseDouble(totalMap.get("data").toString());
				if (selectType.equals("single")) { // 如果是单车数据
					for (Map yieldMap : yieldData) {
						String factory2 = (String) CommonConstants.devIdFactory.get(yieldMap.get("devId"));
						String time2 = (String) yieldMap.get("time");
						if (factory1.equals(factory2) && time1.equals(time2)) {
							double yield = Double.parseDouble(yieldMap.get("data").toString()); // 当前架构下的产量
							if (yield == 0) { // 如果产量为0，计算没有意义
								data = 0;
							} else {
								data = (data / yield);
							}
							break;
						}
					}
				}
				datas.add(data);
			}
		}
		return datas;
	}


	/**
	 * 得到PV计算的总数据
	 * @param nowData 当前总数据
	 * @param preData 环比时间总数据
	 * @param selectType 用量还是单车
	 * @param type 能源类型
	 * @return
	 */
	public List<Map> getPVFactoryData(double nowData, double preData, String selectType, String type) {
    	List<Map> result = new ArrayList<>();
		double ringValue = 0;
		if (preData != 0) {
			ringValue = (nowData - preData) / preData;
		}
		String increase = UServ.retainDecimal(100 * ringValue, "0") + "%";
		String energy = (String) CommonConstants.comEnergy.get(selectType + type);
		Map map = new HashMap();
		map.put("rank", 1);
		map.put("name", "PV");
		map.put("useNum", getDataConver(selectType, type, nowData));
		map.put("increase", increase);
		map.put("energy", energy);
		result.add(map);
		return result;
	}


	/**
	 * 计算环比，排名后的最终数据
	 * @param workSpaceName 空间名称
	 * @param selectType 用量还是单车
	 * @param type 能源类型
	 * @param targetIdArr 架构id数组
	 * @param totalData 计算数据
	 * @param yieldData 产量数据
	 * @return
	 */
	public List<Map> totalSingleRingData(String workSpaceName, String selectType, String type, Long[] targetIdArr, List<Map<String, Object>> totalData, List<Map<String, Object>> yieldData) {
		String[] spaceNames = workSpaceName.split("/"); // 空间长度
		List<EnergyStruc> energyStrucs = energyStrucRepo.getByIdIn(targetIdArr);
		Map strucIdFactory = Collections3.extractToMap(energyStrucs, "id", "factory"); // 架构id和工厂factory的对应关系
		List<Map> resultList = new ArrayList<>();
		double pvNowData = 0;
		double pvPreData = 0;
		for (int i = 0; i < targetIdArr.length; i++) {
			Long targetId = targetIdArr[i];
			List<Double> datas = totalSingleData(targetId, selectType, strucIdFactory, totalData, yieldData);
			double nowData = datas.get(1); // 当前数据
			double preData = datas.get(0); // 环比数据
			pvNowData += nowData; // PV当前总数据
			pvPreData += preData; // PV环比时间总数据
			if (spaceNames.length == 1) { // 如果是统计PV数据，不用进行下面的计算了
				continue;
			}
			// 开始计算环比数据
			double ringValue = 0;
			if (preData != 0) {
				ringValue = (nowData - preData) / preData;
			}
			String increase = UServ.retainDecimal(100 * ringValue, "0") + "%";
			String energy = (String) CommonConstants.comEnergy.get(selectType + type);
			String energyName = (String) strucIdFactory.get(targetId); // 对应工厂
			if (spaceNames.length == 3) {
				energyName += "/" + spaceNames[2];
			}
			Map map = new HashMap();
			map.put("name", energyName);
			map.put("useNum", getDataConver(selectType, type, nowData));
			map.put("increase", increase);
			map.put("energy", energy);
			resultList.add(map);
		}
		// 如果是计算PV的数据把所有工厂的数据加起来
		if (spaceNames.length == 1) {
			return getPVFactoryData(pvNowData, pvPreData, selectType, type);
		}
		// 按照useNum进行降序排列
		Collections.sort(resultList, (o1, o2) -> {
            Double value1 = Double.parseDouble(o1.get("useNum").toString());
            Double value2 = Double.parseDouble(o2.get("useNum").toString());
            return value2.compareTo(value1);
        });
		// 给resultList加上排名
		for (int i = 0; i < resultList.size(); i++) {
			Map map = resultList.get(i);
			map.put("rank", i + 1);
		}
		return resultList;
	}


    /**
     * 根据time获取数据库DateFormat格式化时间
     * @param time
     * @return
     */
	public String dateFormatTime(String time) {
	    String format = "";
	    if (time.length() == 4) {
	        format = "%Y";
        }
        if (time.length() == 7) {
	        format = "%Y-%m";
        }
        if (time.length() == 10) {
	        format = "%Y-%m-%d";
        }
        return format;
    }


	/**
	 * 根据时间粒度来获取格式化时间
	 * @param timeLevel 时间粒度
	 * @return
	 */
	public String timeDateFormat(int timeLevel) {
		String format = "%Y";
		if (timeLevel == 2) {
			return "%Y-%m";
		} else if (timeLevel == 3){
			return "%Y-%m-%d";
		}else if (timeLevel == 4){
			return "%Y-%m-%d %H";
		}
		return format;
	}


	/**
	 * 根据时间粒度和时间获取下一个时间(因为数据库win表的时间字段是字符串，所以时间过滤数据会有问题，endTime需要对应加+1)
	 * @param timeLevel 时间粒度(1：年 2：月 3：日 4：小时)
	 * @param endTime 时间
	 * @return
	 */
	public String getNextTime(int timeLevel, String endTime) {
		if (timeLevel == 1) {
			return "" + (Integer.parseInt(endTime.substring(0, 4)) + 1);
		}
		String format = "yyyy-MM"; // 默认是月份间隔
		int calendarType = Calendar.MONTH;
		if (timeLevel == 3 || timeLevel == 4) {
			format = "yyyy-MM-dd";
			calendarType = Calendar.DATE;
		}
		Date time = null;
		try {
			time = DateUtil.getDateByStrTime(endTime, format);
		} catch (ParseException e) {
			e.printStackTrace();
		}
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(time);
		calendar.add(calendarType, +1);
		return DateUtil.getStringDate(calendar.getTime(), format);
	}


	/**
	 * 根据时间粒度截取对应时间的格式化时间
	 * @param startTime 时间
	 * @param timeLevel 时间粒度
	 * @return
	 */
	public String subTimebyTimeLevel(int timeLevel, String startTime) {
		if (timeLevel == 1) {
			return startTime.substring(0, 4);
		}
		if (timeLevel == 2) {
			return startTime.substring(0, 7);
		}
		return startTime;
	}


    /**
     * 数据的小数点保留规则判断(小于100，保留一位小数，大于100，去掉小数)
     * @param dataType 数据类型
     * @param energy 能源
     * @param value 数值
     * @return
     */
	public Object getDataConver(String dataType, String energy, double value) {
        if (energy.contains("碳排") || energy.contains("成本")) { // 如果是碳排和成本，数值需要除以1000
            if (dataType.equals("total")) { // 计算总量才需要除以1000
                value = (value / 1000);
            }
        }
        Object newValue;
        if (value <= 100) {
            newValue = UServ.retainDecimal(value, "0");
        } else {
        	newValue = (int) value; // 去掉小数
        }
        return newValue;
    }


	/**
	 * 生成两个时间内以年份为间隔的时间集合
	 * @param startTime 开始时间
	 * @param endTime 结束时间
	 * @return
	 */
	public List<String> getYearsTimeList(String startTime, String endTime) {
		List<String> yearList = new ArrayList<>();
		String startYear = startTime.substring(0, 4);
		String endYear = endTime.substring(0, 4);
		String year = startYear;
		while (true) {
			yearList.add(year);
			if (year.equals(endYear)) {
				return yearList;
			}
			String nextYear = "" + (Integer.parseInt(year) + 1);
			year = nextYear;
		}
	}


	/**
	 * 生成两个时间内指定间隔的时间集合
	 * @param timeLevel 时间粒度(1：年 2：月 3：日 4：小时)
	 * @param startTime 开始时间
	 * @param endTime 结束时间
	 * @return
	 */
	public List<String> getTimeList(int timeLevel, String startTime, String endTime) throws ParseException {
		if (timeLevel == 1) {
			return getYearsTimeList(startTime, endTime);
		}
		String format = "yyyy-MM"; // 默认粒度为2, 间隔为月份
		int calendarType = Calendar.MONTH;
		String start = startTime.substring(0, 7);
		String end = endTime.substring(0, 7);
		if (timeLevel == 3) { // 间隔为天
			format = "yyyy-MM-dd";
			calendarType = Calendar.DATE;
			start = startTime;
			end = endTime;
		}
		if (timeLevel == 4) { // 间隔为小时
			format = "yyyy-MM-dd HH";
			calendarType = Calendar.HOUR_OF_DAY;
			start = startTime + " 00";
			end = endTime + " 23";
		}
		List<String> timeList = new ArrayList<>();
		String date = start;
		while (true) {
			timeList.add(date); // 添加第一个月份
			if (date.equals(end)) { // 遍历到结束
				return timeList;
			}
			Date time = DateUtil.getDateByStrTime(date, format);
			Calendar calendar = Calendar.getInstance();
			calendar.setTime(time);
			calendar.add(calendarType, +1);
			date = DateUtil.getStringDate(calendar.getTime(), format);
		}
	}


	/**
	 * 字符串转成Long类型的数组
	 * @param target 以逗号组成的目标id字符串
	 * @return
	 */
	public Long[] stringToLongArr(String target) {
		String[] ids = target.split(",");
		Long[] longArr = new Long[ids.length];
		for (int i = 0; i < ids.length; i++) {
			longArr[i] = Long.parseLong(ids[i]);
		}
		return longArr;
	}


	/**
	 * 给没有时间段的用量数据补0
	 * @param targetIdArr 对比的架构能源
	 * @param timeList 时间颗粒数组
	 * @param totalList 数据库查询出来的用量数据
	 * @return
	 */
	public List getTotalResult(Long[] targetIdArr, List<String> timeList, List<Map<String, Object>> totalList) {
		List<EnergyStruc> energyStrucs = energyStrucRepo.getByIdIn(targetIdArr);
		Map strucIdFactory = Collections3.extractToMap(energyStrucs, "id", "factory"); // 架构id和工厂factory的对应关系
		Map strucIdEnergy = Collections3.extractToMap(energyStrucs, "id", "type"); // 架构id和能源energy的对应关系
		List resultList = new ArrayList<Map<String, Object>>();
		for (int i = 0; i < targetIdArr.length; i++) {
			Long targetId1 = targetIdArr[i];
			for (String time : timeList) {
				Object data = 0;
				for (Map map : totalList) {
					Long targetId2 = (Long) map.get("targetId");
					if (targetId1.equals(targetId2) && time.equals(map.get("time"))) {
						data = map.get("data");
						break;
					}
				}
				Map map = new HashMap<String, Object>();
				map.put("factory", strucIdFactory.get(targetId1));
				map.put("energy", strucIdEnergy.get(targetId1));
				map.put("targetId", targetIdArr[i]);
				map.put("time", time);
				map.put("data", data);
				resultList.add(map);
			}
		}
		return resultList;
	}


	/**
	 * 数字字符串id转换成int类型数组
	 * @param ids 目标字符串id
	 * @return
	 */
	public int[] stringToIntArr(String ids) {
		String[] idArr = ids.split(",");
		int[] result = new int[idArr.length];
		for (int i = 0; i < idArr.length; i++) {
			result[i] = Integer.parseInt(idArr[i]);
		}
		return result;
	}


	/**
	 * 给没有时间段的产量数据补0
	 * @param times 时间颗粒数组
	 * @param yieldList 数据库查询出来的产量数据
	 * @return
	 */
	public List getYieldResult(List<String> times, List<Map<String, Object>> yieldList) {
		List resultList = new ArrayList<Map<String, Object>>();
		int[] devIds = stringToIntArr(yieldDevIds);
		for (int devId : devIds) {
			String factory1 = (String) CommonConstants.devIdFactory.get(devId);
			for (String time : times) {
				Object data = 0;
				for (Map map : yieldList) {
					String factory2 = (String) CommonConstants.devIdFactory.get(map.get("dev_id"));
					if (factory1.equals(factory2) && time.equals(map.get("time"))) {
						data = map.get("data");
						break;
					}
				}
				Map map = new HashMap<String, Object>();
				map.put("devId", devId);
				map.put("time", time);
				map.put("data", data);
				resultList.add(map);
			}
		}
		return resultList;
	}


	/**
	 * 查询数据的SQL语句map
	 * @param energy 能源类型
	 * @param targetName 对比的架构名称
	 * @param timeLevel 时间粒度(1：年 2：月 3：日 4：小时)
	 * @param startTime 开始时间
	 * @param endTime 结束时间
	 * @return
	 */
	public Map getDataSqlMap(String energy, String targetName, int timeLevel, String startTime, String endTime) {
		String targetIds; // 对比的目标对象架构id
		if (energy.contains("碳排") || energy.contains("成本")) {
			targetIds = iotJsService.getEnergyStrucIdsByName(targetName); // 当前对比所有空间的电和燃气的架构id数据
		} else {
			targetIds = iotJsService.getEnergyStrucIdsByNameType(targetName, energy);
		}
		// 因为win表的时间类型是字符串，所以通过时间过滤时间会有问题，endTime需要加一年，一个月，一天，一个小时才可以
		String subStartTime = subTimebyTimeLevel(timeLevel, startTime);
		String nextTime = getNextTime(timeLevel, endTime);
		String totalSql = "select esp.energy_struc_id targetId, DATE_FORMAT(win.the_time,'" + timeDateFormat(timeLevel) + "') time, sum(win.dvalue) data" +
				" from iot_dev_data_win win inner join energy_struc_prop esp on win.dev_id = esp.dev_id and win.data_type = esp.name" +
				" where esp.type = 1 and esp.field_type = '用量' and esp.energy_struc_id in (" + targetIds + ")" +
				" and win.the_time >= '" + subStartTime + "' and win.the_time < '" + nextTime + "' group by targetId, time";
		String yieldSql = "select dev_id, DATE_FORMAT(the_time,'" + timeDateFormat(timeLevel) + "') time, sum(dvalue) data from iot_dev_data_win" +
				" where dev_id in (" + yieldDevIds + ") and the_time >= '"+ subStartTime +"' and the_time < '" + nextTime + "' group by dev_id, time";
		Map sqlMap = new HashMap();
		sqlMap.put("totalSql", totalSql);
		sqlMap.put("yieldSql", yieldSql);
		sqlMap.put("targetIds", targetIds);
		return sqlMap;
	}


	/**
	 * 处理数据(碳排或者成本数据 = 电数据 * 电系数 + 燃气数据 * 燃气系数，组装成碳排或者成本的总数据)
	 * @param energy 能源
	 * @param targetIdNameMap 能源架构id和能源架构全称的对应关系Map
	 * @param resultData 需要组装的数据
	 * @return
	 */
	public List carbonCostDataDealWith(String energy, Map targetIdNameMap, List<Map<String, Object>> resultData) {
		List<Map> dealWithData = new ArrayList<>();
		String carbonCost = energy.equals("碳排") ? "carbon" : "cost"; // 碳排和成本的英文key
		List<String> keyList = new ArrayList<>(); // 架构和time组成的唯一标记集合
		for (Map map1 : resultData) {
			Long targetId1 = (Long) map1.get("targetId");
			String targetName1 = (String) targetIdNameMap.get(targetId1);
			String time1 = (String) map1.get("time");
			String mapKey = targetName1 + time1;
			if (keyList.contains(mapKey)) { // 避免对比同个架构下的同年份数据
				continue;
			}
			keyList.add(mapKey);
			String factory1 = (String) map1.get("factory");
			String erengy1 = map1.get("energy").equals("电") ? "ele" : "gas";
			String time1Year = time1.substring(0, 4);
			String key1 = carbonCost + factory1 + time1Year + erengy1;
			Object modulus1 = CommonConstants.modulus.get(key1);
			double m1 = (modulus1 == null ? 0 : (double) modulus1);
			Double data1 = Double.parseDouble(map1.get("data").toString());
			for (Map map2 : resultData) {
				Long targetId2 = (Long) map2.get("targetId");
				String targetName2 = (String) targetIdNameMap.get(targetId2);
				String time2 = (String) map2.get("time");
				if (!targetId1.equals(targetId2) && targetName1.equals(targetName2) && time1.equals(time2)) {
					String erengy2 = map2.get("energy").equals("电") ? "ele" : "gas";
					String time2Year = time2.substring(0, 4);
					String factory2 = (String) map2.get("factory");
					String key2 = carbonCost + factory2 + time2Year + erengy2;
					Object modulus2 = CommonConstants.modulus.get(key2);
					double m2 = (modulus2 == null ? 0 : (double) modulus2);
					Double data2 = Double.parseDouble(map2.get("data").toString());
					double data = data1 * m1 + data2 * m2; // 电 * 系数 + 燃气 * 系数
					Map dealWithMap = new HashMap();
					dealWithMap.put("factory", factory1);
					dealWithMap.put("targetName", targetName1);
					dealWithMap.put("time", time1);
					dealWithMap.put("data", data);
					dealWithData.add(dealWithMap);
					break;
				}
			}
		}
		return dealWithData;
	}


	/**
	 * 数据对比统计结果：计算碳排和成本的数据，2019年之后和2019年之前的计算逻辑是不一样的
	 * 2019年之后：直接查询win表(因为计算逻辑很复杂，暂时先统一用2019年之前的计算逻辑，电*系数+燃气*系数)
	 * 2019之前：电的数据 * 电系数 + 燃气的数据 * 燃气系数
	 * @param dataType 数据类型：用量还是单车用量
	 * @param energy 能源类型
	 * @param targetName 对比的架构名称
	 * @param timeLevel 时间粒度(1：年 2：月 3：日 4：小时)
	 * @param startTime 开始时间
	 * @param endTime 结束时间
	 * @return
	 */
	public List<Map> carbonCostComparisonData(String dataType, String energy, String targetName, int timeLevel, String startTime, String endTime) {
		Map sqlMap = getDataSqlMap(energy, targetName, timeLevel, startTime, endTime);
		SqlHelper sqlHelper = getSqlHelper();
		List<Map> result = new ArrayList<>();
		try {
			List<Map<String,Object>> totalResult = sqlHelper.queryList((String) sqlMap.get("totalSql")); // 计算用量数据
			List<Map<String, Object>> yieldResult = null;
			if (dataType.equals("single")) { // 如果是计算单车用量数据
				yieldResult = sqlHelper.queryList((String) sqlMap.get("yieldSql"));
			}
			String[] targetNames = targetName.split(",");
			Map targetIdNameMap = new HashMap(); // 架构id和架构全称的对应关系map
			String targetIds = sqlMap.get("targetIds").toString();
			Long[] targetIdArr = stringToLongArr(targetIds);
			// 把totalResult里面的架构id转换成架构全称targetName
			for (Long targetId : targetIdArr) {
				String energyName = spaceService.getEnergyFullName(targetId);
				targetIdNameMap.put(targetId, energyName);
			}
			List<String> timeList = getTimeList(timeLevel, startTime, endTime);
			// 给没有时间段的数据补0
			totalResult = getTotalResult(targetIdArr, timeList, totalResult); // 用量数据补0
			if (dataType.equals("single")) {
				yieldResult = getYieldResult(timeList, yieldResult); // 产量数据补0
			}
			// 数据处理：最终碳排和成本的结果是电*系数+燃气*系数
			List<Map> resultData = carbonCostDataDealWith(energy, targetIdNameMap, totalResult); // 电+燃气处理后的数据
			// 开始遍历组装数据
			for (String name : targetNames) {
				List<Object[]> resultList = new ArrayList<>();
				for (Map map : resultData) {
					if (name.equals(map.get("targetName"))) {
						Object[] data = totalSingleData(yieldResult, timeLevel, dataType, energy, map);
						resultList.add(data);
					}
				}
				// 组装每一个对比架构下的数据对象
				Map mapData = new HashMap<String, Object>();
				mapData.put("name", name);
				mapData.put("data", resultList);
				result.add(mapData);
			}
		} catch (SQLException e) {
			e.printStackTrace();
		} catch (ParseException e) {
			e.printStackTrace();
		}
		return result;
	}


	/**
	 * 组装用量数据和单车数据
	 * @param yieldResult 产量数据
	 * @param timeLevel 时间粒度
	 * @param dataType 数据类型
	 * @param energy 能源类型
	 * @param map 当前用量map
	 * @return
	 */
	public Object[] totalSingleData(List<Map<String, Object>> yieldResult, int timeLevel, String dataType, String energy, Map map) {
		Object[] data = new Object[2];
		String time = (String) map.get("time");
		if (timeLevel == 4) {
			time = time.substring(5);
		}
		data[0] = time;
		Double value = Double.parseDouble(map.get("data").toString());
		if (dataType.equals("total")) { // 用量数据
			data[1] = getDataConver(dataType, energy, value);
		} else { // 单车用量数据
			int yieldSize = yieldResult.size();
			for (int i = 0; i < yieldSize; i++) {
				Map yieldMap = yieldResult.get(i);
				String factory = (String) CommonConstants.devIdFactory.get(yieldMap.get("devId"));
				if (map.get("factory").equals(factory) && map.get("time").equals(yieldMap.get("time"))) {
					double yield = Double.parseDouble(yieldMap.get("data").toString()); // 当前架构下的产量
					if (value == 0 || yield == 0) { // 如果用量或者产量为0，计算没有意义
						data[1] = 0;
					} else {
						value = (value / yield); // 单车用量
						data[1] = getDataConver(dataType, energy, value);
					}
					break;
				}
			}
		}
		return data;
	}


	/**
	 * 数据对比统计结果：计算电，水，燃气，蒸汽，冷量，压缩空气的数据，2019年之后和2019之前的计算逻辑一样的
	 * @param dataType 数据类型：用量还是单车用量
	 * @param energy 能源类型
	 * @param targetName 对比的架构名称
	 * @param timeLevel 时间粒度(1：年 2：月 3：日 4：小时)
	 * @param startTime 开始时间
	 * @param endTime 结束时间
	 * @return
	 */
	public List<Map> otherComparisonData(String dataType, String energy, String targetName, int timeLevel, String startTime, String endTime) {
		String targetIds = iotJsService.getEnergyStrucIdsByNameType(targetName, energy); // 对比的目标对象架构id
		List<Map> result = new ArrayList<>(); // 返回数据类型
		Map sqlMap = getDataSqlMap(energy, targetName, timeLevel, startTime, endTime);
		try {
			SqlHelper sqlHelper = getSqlHelper();
			List<Map<String,Object>> totalResult = sqlHelper.queryList((String) sqlMap.get("totalSql")); // 计算用量数据
			List<Map<String, Object>> yieldResult = null;
			if (dataType.equals("single")) { // 如果是计算单车用量数据
				yieldResult = sqlHelper.queryList((String) sqlMap.get("yieldSql"));
			}
			String[] targetNames = targetName.split(",");
			List<String> timeList = getTimeList(timeLevel, startTime, endTime);
			// 给没有时间段的数据补0
			Long[] targetIdArr = stringToLongArr(targetIds);
			totalResult = getTotalResult(targetIdArr, timeList, totalResult);
			if (dataType.equals("single")) {
				yieldResult = getYieldResult(timeList, yieldResult);
			}
			// 开始遍历组装数据
			for (int i = 0; i < targetIdArr.length; i++) {
				List<Object[]> resultArr = new ArrayList<>();
				int resultSize = totalResult.size();
				for (int j = 0; j < resultSize; j++) { // 遍历所有架构的用量数据
					Map map = totalResult.get(j);
					Long targetId = (Long) map.get("targetId");
					if (targetIdArr[i].equals(targetId)) { // 如果架构id一样
						Object[] data = totalSingleData(yieldResult, timeLevel, dataType, energy, map);
						resultArr.add(data);
					}
				}
				// 组装每一个对比架构下的数据对象
				Map mapData = new HashMap<String, Object>();
				mapData.put("name", targetNames[i]);
				mapData.put("data", resultArr.toArray());
				result.add(mapData);
			}
		} catch (SQLException e) {
			e.printStackTrace();
		} catch (ParseException e) {
			e.printStackTrace();
		}
		return result;
	}


	/**
	 * 工厂数据对比结果
	 * @param json 参数
	 * @return
	 */
//	public Map factoryComparison(String json) {
//		JSONObject param = JSONObject.parseObject(json);
//		String dataType = param.getString("dataType");
//		String energy = param.getString("energy");
//		int timeLevel = param.getIntValue("timeLevel"); // 时间粒度(1：年 2：月 3：日 4：小时)
//		String startTime = param.getString("startTime");
//		String endTime = param.getString("endTime");
//		List<EnergyStruc> energyList = energyStrucRepo.findAllByLevelAndType(1, energy);
//		String targetName = Collections3.extractToString(energyList, "name", ",");
//		List<Map> resultData = otherComparisonData(dataType, energy, targetName, timeLevel, startTime, endTime);
//		Map resultMap = new HashMap<String, Object>();
//		resultMap.put("factory", Collections3.extractToList(energyList, "name").toArray());
//		resultMap.put("data", resultData);
//		return resultMap;
//	}


	/**
	 * 车间数据对比结果
	 * @param json 参数
	 * @return
	 */
//	public Map workshopComparison(String json) {
//		JSONObject param = JSONObject.parseObject(json);
//		String dataType = param.getString("dataType");
//		String energy = param.getString("energy");
//		String workshop = param.getString("workshop"); // 车间名称
//		int timeLevel = param.getIntValue("timeLevel"); // 时间粒度(1：年 2：月 3：日 4：小时)
//		String startTime = param.getString("startTime");
//		String endTime = param.getString("endTime");
//		List<EnergyStruc> workshopList = energyStrucRepo.findAllByNameAndType(workshop, energy);
//		List<EnergyStruc> factoryList = energyStrucRepo.findAllByLevelAndType(1, energy);
//		String targetName = Collections3.extractToString(factoryList, "name", ",");
//		List<Map> resultData = otherComparisonData(dataType, energy, targetName, timeLevel, startTime, endTime);
//		Map resultMap = new HashMap<String, Object>();
//		List factorys = Collections3.extractToList(factoryList, "name");
//		if (workshopList.isEmpty()) { // 没有车间能源架构
//			factorys = new ArrayList();
//			resultData = new ArrayList<>();
//		}
//        resultMap.put("factory", factorys);
//        resultMap.put("data", resultData);
//        return resultMap;
//	}


	/**
	 * 自定义走势对比
	 * @param params
	 */
	public List<Map> customizeComparison(Map params) {
		String dataType = (String) params.get("dataType"); // 数据类型，用量：total，单车用量：single
		String energy = (String) params.get("energy"); // 能源类型
		String targetName = (String) params.get("targetName"); // 对比的目标对象名称
		int timeLevel = (int) params.get("timeLevel"); // 时间粒度(1：年 2：月 3：日 4：小时)
		String startTime = (String) params.get("startTime"); // 开始时间
		String endTime = (String) params.get("endTime"); // 结束时间
		List<Map> resultData;
		if (energy.equals("碳排") || energy.equals("成本")) { // 碳排和成本的查询计算逻辑
			resultData = carbonCostComparisonData(dataType, energy, targetName, timeLevel, startTime, endTime);
		} else { // 其他能源的查询计算逻辑
			resultData = otherComparisonData(dataType, energy, targetName, timeLevel, startTime, endTime);
		}
		return resultData;
	}


	/**
	 * 插入，批量保存
	 *
	 * @param list 实体集合
	 * @return List<T>
	 */
	@Override
	public List<IotDev> insertObjInBatch (List<IotDev> list) {
		return null;
	}

	/**
	 * 更新
	 *
	 * @param device 跟新的实体
	 * @return T
	 */
	@Transactional(rollbackOn = Exception.class)
	@DevToCache
	@Override
	public IotDev update (IotDev device) {

		IotDev dbResult = deviceRepo.saveAndFlush(device);

		return dbResult;
	}

	/**
	 * 删除--批量删除
	 *
	 * @param ids 批量删除id
	 * @return int 影响数
	 */
	@Transactional(rollbackOn = Exception.class)
	@Override
	public int delete (Long[] ids) {
		int effections = deviceRepo.deleteByIdIn(ids);
		if (effections > 0) {
			for (int i = 0; i < ids.length; i++) {
				IotDev iotDev = new IotDev();
				iotDev.setId(ids[i]);
				devFollowRepo.deleteDevFollowsByDevice(iotDev);
			}
		}
		if (effections > 0){
			for (int i = 0; i < ids.length; i++) {
				devFollowRepo.deleteEnergyStrucPropByDevId(ids[i]);
			}
		}
		return effections;
	}


	/**
	 * 通过空间id验证是否与设备与其关联，如果存在依赖关系，则此设备不允许被删除
	 * @param ids 空间ids
	 * @return
	 */
	public boolean spaceDevHasDependency(Long[] ids) {
		long spaceId = ids[0];
		List<Long> spaceIds = deviceRepo.findIdsBySpaceId(spaceId);
		if (Collections3.isEmpty(spaceIds)) {
			return false;
		}
		return true;
	}


	/**
	 * 验证当前设备类型=是否被相关设备依赖，如果存在依赖关系，则此设备类型不允许被删除
	 * @param ids 设备类型ids
	 * @return
	 */
	public boolean checkDeviceHasDependency(Long[] ids) {
		Long devTypeId = ids[0];
		List<Integer> iotDevList = deviceRepo.findDevByDevTypeId(devTypeId);
		if (Collections3.isEmpty(iotDevList)) {
			return false;
		}
		return true;
	}


	/**
	 * 获取列表数据---使用 com.mach.platform.utils.springdata  下的DynamicSpecifications 的
	 * 写法进行分页查询
	 *
	 * @param pageable 分页参数
	 * @param params   其他参数
	 * @return Page<T>
	 */
	@Override
	public Page<IotDev> list (Pageable pageable, Map params) {
        pageable.getSort().and(Sort.by(new String[] { "id desc"}));
		Specification specification = DynamicSpecifications.bySearchFilter(SearchFilter.parse(params).values(), IotDev.class);

        Page<IotDev> dbResult = deviceRepo.findAll(specification, pageable);
        for (IotDev iotDev : dbResult) {
            IotSpace space = iotDev.getIotSpace();
            if (space != null){
                Object cacheResult = CacheUtils.guavaCacheFactory.getIfPresent(CommonConstants.SPACE_LEVEL_PREFIX + space.getId());
                if (cacheResult == null) {
                    String lvSpace = spaceService.queryParent(space.getId());
					if (lvSpace != null) {
                    	iotDev.setTemporaryVariable(lvSpace);
						CacheUtils.guavaCacheFactory.put(CommonConstants.SPACE_LEVEL_PREFIX + space.getId(), lvSpace);
					}
				} else {
                    iotDev.setTemporaryVariable(cacheResult.toString());
                }
            }
        }
		return dbResult;
	}


	/**
	 * 获取单体 数据
	 * @param id 获取详情的id
	 * @return T
	 */
	@DevCache
	@Override
	public IotDev info (Long id) {
		return deviceRepo.getById(id);
	}

	/**
	 * 加载关联的到某空间的所有设备数据
	 * @param iotSpace
	 * @return
	 */
	public List<IotDev> LoadAllDevsByIotSpace (IotSpace iotSpace) {
		List<IotDev> dbResult = deviceRepo.getAllByIotSpace(iotSpace);
		//获取关注的信息
//		List<DevFollow> followRelations = devFollowRepo.getAllByUser(SecurityUtils.getCurrentUserByAccountDomain());

		if (dbResult.size() > 0) {
			for (int i = 0; i < dbResult.size(); i++) {
				IotDev iotDev = dbResult.get(i);
				// 拼接空间节点文本
				IotSpace space = iotDev.getIotSpace();
				if (space != null) {
					String spaceText = spaceService.queryParent(space.getId());
					iotDev.setTemporaryVariable(spaceText);
				}
				// 匹配关注信息
//				DevFollow matchBbj = followRelations.stream().filter(item->item.getDevice().getId().equals(iotDev.getId())).findFirst().orElse(null);
//				if (matchBbj == null) {
//					iotDev.setFollow(false);
//					// todo delete
//					iotDev.setStatus(1);
//				} else {
//					iotDev.setFollow(true);
//					// todo delete
//					iotDev.setStatus(1);
//				}
			}
		}
		return dbResult;
	}


	/**
	 * 查询设备相关属性最新数据
	 * @param iotDev 设备对象
	 * @param type 属性类型
	 * @param time 查询时间
	 * @return
	 */
	public List getDevItemData(IotDev iotDev, String type, String time) {
		String winTableName = "iot_dev_data_win"; // 默认查询win表
		String timeGrain = UServ.getTimeByFormat(time); // 分钟粒度，查询win_minute表数据
		if (timeGrain.equals("hour")) {
			winTableName = "iot_dev_data_win_minute";
		}
		String dvalueType = "dvalue"; // 默认是查询瞬时数据
		if (type.contains("累积")) {
			dvalueType = "sum(dvalue)";
		}
		String tableName = "iot_virtual_item"; // 默认是虚拟设备
		if (iotDev.getType() == 0) { // 如果是真实设备
			tableName = "iot_coll_items";
		}
		String formatTime = UServ.getPatternTime(time);
		String sql = "select item.name, item.unit, " + dvalueType + " value, DATE_FORMAT(win.the_time, '" + formatTime + "') time from " + winTableName + " win" +
				" left join " + tableName + " item on item.name = win.data_type" +
				" where win.dev_id = " + iotDev.getId() + " and item.type = '" + type + "' and win.the_time like '" + time + "%'" +
				" group by item.name, time";
		List<Map<String,Object>> mapList = null;
		SqlHelper sqlHelper = getSqlHelper();
		try {
			mapList = sqlHelper.queryList(sql);
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return mapList;
	}


	/**
	 * 生成设备属性数据的Excel
	 * @param list Excel里面的数据
	 * @param time 查询时间
	 * @return
	 */
	public XSSFWorkbook createItemDataExcel(List<Map<String,Object>> list, String time) throws ParseException {
		XSSFWorkbook workbook = new XSSFWorkbook();
		Sheet sheet = workbook.createSheet("设备属性表");
		if (Collections3.isEmpty(list)) {
			return workbook;
		}
		Row row = sheet.createRow(0);
		List<String> itemList = getItemList(list);
		// 组装表头数据
		for (int i = 0; i < itemList.size(); i++) {
			Cell cell = row.createCell(i + 1);
			cell.setCellValue(itemList.get(i));
		}
		String[] timeArr = UServ.getTimeArrByTime(time);
		// 开始组装所有的设备属性数据
		for (int i = 0; i < timeArr.length; i++) {
			// 得到当前行数的下一行
			row = sheet.createRow(row.getRowNum() + 1);
			for (int j = 0; j <= itemList.size(); j++) {
				if (j == 0) {
					row.createCell(j).setCellValue(timeArr[i]);
				} else {
					// 给没有对应时间的数据补0
					double data = 0;
					for (Map<String, Object> map : list) {
						String itemName = (String) map.get("name");
						String itemTime = (String) map.get("time");
						if (itemList.get(j - 1).equals(itemName) && timeArr[i].equals(itemTime)) {
							data = (double) map.get("value");
						}
					}
					row.createCell(j).setCellValue(data);
				}
			}
		}
		return workbook;
	}


	/**
	 * 获取属性单位
	 * @param iotDev
	 * @param type
	 * @return
	 */
	public String getItemUnit(IotDev iotDev, String type) {
		SqlHelper sqlHelper = getSqlHelper();
		String tableName = "iot_virtual_item"; // 默认是虚拟设备
		if (iotDev.getType() == 0) { // 如果是真实设备
			tableName = "iot_coll_items";
		}
		String sql = "select unit from " + tableName + " where type = '" + type + "' and unit is not null limit 1";
		Map<String, Object> result;
		String unit = "";
		try {
			result = sqlHelper.queryOne(sql);
			unit = "(" + type + "/" + result.get("unit") + ")";
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return unit;
	}


	/**
	 * 将设备相关属性数据组装成前端需要的数据结构
	 * @param devId 设备id
	 * @param type 属性类型
	 * @param time 查询时间
	 * @return
	 */
	public Map<String, Object> devItemData(Long devId, String type, String time) throws ParseException {
		Map<String, Object> result = new HashMap<>(2);
		Map<String, Object> resultMap = new HashMap<>(20);
		List<Map<String, Object>> yaxisMap = new ArrayList<>();

		// 根据time获取下级分段数据
		String[] xaxis = UServ.getTimeArrByTime(time);
		String xUnit = getTimeFormat(time);
		Map<String, Object> xData = new HashMap<>(16);
		xData.put("data", xaxis);
		xData.put("name", xUnit);

		IotDev iotDev = getIotDevById(devId);
		String yUnit = getItemUnit(iotDev, type);
		// 数据库查询相关数据
		List<Map<String,Object>> mapList = getDevItemData(iotDev, type, time);
		// 获取所有属性
		List<String> legendList = getItemList(mapList);
		//遍历mapList添加yaxis的数据
		for (String item : legendList) {
			int length = xaxis.length;
			double[] datas = new double[length];
			//以xaxis时间数据长度为主，和mapList集合对比每个分段的数据，没有数据补0
			for (int i = 0; i < length; i++) {
				double data = 0;
				for (Map<String, Object> map : mapList) {
					String itemName = (String) map.get("name");
					String itemTime = (String) map.get("time");
					if (item.equals(itemName) && xaxis[i].equals(itemTime)) {
						data = (double) map.get("value");
					}
				}
				datas[i] = data;
			}
			Map<String, Object> objectMap = new HashMap<>(16);
			objectMap.put("name", item);
			objectMap.put("data", datas);
			yaxisMap.add(objectMap);
		}
		resultMap.put("legend", legendList.toArray());
		resultMap.put("xAxis", xData);
		resultMap.put("series", yaxisMap.toArray());
		resultMap.put("yUnit", yUnit);
		result.put("data", resultMap);
		return result;
	}


	/**
	 * 抽取属性数据里面的全部属性
	 * @param list
	 * @return
	 */
	public List<String> getItemList(List<Map<String, Object>> list) {
		List<String> itemList = new ArrayList<>();
		for (Map<String, Object> map : list) {
			String itemName = (String) map.get("name");
			if (!itemList.contains(itemName)) {
				itemList.add(itemName);
			}
		}
		return itemList;
	}


	/**
	 * 根据时间获取下级时间：月,日，分钟，秒
	 * @param time
	 * @return
	 */
	public static String getTimeFormat(String time) {
		if (time.length() == 4) {
			return "(月)";
		} else if (time.length() == 7) {
			return "(日)";
		} else if (time.length() == 10){
			return "(小时)";
		}else if (time.length() == 13){
			return "(分钟)";
		} else if (time.length() == 16) {
			return "(秒)";
		} else {
			return "(其他)";
		}
	}


	/**
	 * 通过设备id查询设备对象
	 * @param id
	 * @return
	 */
	public IotDev getIotDevById(Long id) {
		return deviceRepo.getById(id);
	}


	/**
	 *  调取实时数据
	 * @param id
	 * @return
	 */
	public IotDev curData(Long id)  {
		SqlHelper sqlHelper = SqlHelper.getBySource(this.dataSource);

		@DevCache
		IotDev dev = Aops.getSelf(this).info(id);
		if(dev == null){
			return null;
		}
		String sql = "select data_type, dev_id, dvalue, unit from iot_dev_cur_data_win win"
				   + " where dev_id = " + id
				   + " and uptime>date_sub(now(), interval 1 HOUR)"
				   + " and uptime is not null";
		if(dev.getType() == 1 || dev.getType() == 2){ //虚拟设备
			IotDevType devType = new IotDevType();
			dev.setIotDevType(devType);
			List<IotVirtualItem> virtualItems = dev.getVirtualItems();
			Map<Object, Map<String, Object>> dbData = Collections.EMPTY_MAP;
			try {
				dbData = sqlHelper.query(sql);
			} catch (SQLException e) {
				e.printStackTrace();
			}
			LinkedList<Object> itemDatas = new LinkedList<>();
			for (IotVirtualItem item : virtualItems) {
				if (item.getIsGet() != 1) {
					continue;
				}

				// 移值
				IotCollItemData data = new IotCollItemData(item);
				data.setPropertyType(item.getPropertyType());
				data.setUnit(item.getUnit());
				data.setName(item.getName());


				// 找值
				for(Map<String, Object> dbItem : dbData.values()){
					String dataType = "";
					try {
						dataType = (String)dbItem.get("data_type");
						Object value = dbItem.get("dvalue");
						Object unit = dbItem.get("unit");
						if (dataType.equals(item.getName())) {
							value = new DecimalFormat("0.00").format(value);
							data.setValue(value);
						}
					} catch (Exception e) {
						log.info("getDataError. dataType=" + dataType + " devId" + id );
					}
				}


				itemDatas.add(data);
			}
			dev.setIotCollItemDatas(itemDatas);
		}
		if(dev.getType() == 0){ //真实设备
			List<IotCollItem> colls = dev.getIotDevType().getIotCollItems();
			Map<Object, Map<String, Object>> dbData = Collections.EMPTY_MAP;
			try {
				dbData = sqlHelper.query(sql);
			} catch (SQLException e) {
				e.printStackTrace();
			}
			Collection<Map<String, Object>> dbDataValues = dbData.values();

			LinkedList<Object> itemDatas = new LinkedList<>();
			for (IotCollItem item : colls){
				if(item.getIsGet() != 1){
					continue;
				}
				IotCollItemData data = new IotCollItemData(item);
				for(Map<String, Object> dbItem :  dbDataValues){
					String dataType = "";
					try {
						dataType = (String)dbItem.get("data_type");
						Object value = dbItem.get("dvalue");
						Object unit = dbItem.get("unit");

						if(dataType.equals(item.getName())){
							value = new DecimalFormat("0.00").format(value);
							data.setValue(value);
							data.setUnit(unit.toString());
						}
					} catch (Exception e) {
						log.info("getDataError. dataType=" + dataType + " devId" + id );
					}
				}
				itemDatas.add(data);
			}
			dev.setIotCollItemDatas(itemDatas);
		}
		return dev;
	}

    /**
     *  调取实时数据
     * @param id
     * @return
     */
    public Map<String,Object> curDevDataHasType(Long id, String dataType)  {

        SqlHelper sqlHelper = SqlHelper.getBySource(this.dataSource);


        Map<String, Object> dbData = Collections.EMPTY_MAP;
        try {
             dbData = sqlHelper.queryOne("select data_type dataType,dev_id devId, dvalue from iot_dev_cur_data_win win where 1=1 " +
                    " and dev_id=" + id +
                    " and data_type='" + dataType + "'"
            );
        } catch (SQLException e) {
            e.printStackTrace();
        }




        return dbData;
    }

	/**
	 * 控制开关
	 * @param devId 设备ID
	 * @param propertyId 属性ID
	 * @param value 前端的数据
	 * @return
	 */
	public Integer doSwitch (Long devId, Long propertyId, Integer value){

		IotDev iotDev = deviceRepo.getById(devId);
		// todo  开关启动设备，最好也更新 实时数据
		try {
			Thread.sleep(2500);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}

		return 200;
	}


	/**
	 * 查询某个空间下所有子级空间所关联的所有设备数据
	 * @param spaceId
	 * @return
	 */
	public List<IotDev> loadSpaceUnderAllDevices (Long spaceId) {

		List<IotSpace> iotSpaces = loadSpaceUnderAllDevicesBeforeSpaceIds(spaceId);

		List<IotDev> followRepoAllById = deviceRepo.findAllByIotSpaceIn(iotSpaces);

		return followRepoAllById;
	}

	/**
	 * 查询某个空间下所有子级空间所关联的所有 组合设备数据
	 * @param spaceId
	 * @return
	 */
	public List<IotDev> loadSpaceUnderAllConbinedDevices (Long spaceId) {

		List<IotSpace> iotSpaces = loadSpaceUnderAllDevicesBeforeSpaceIds(spaceId);

		List<IotDev> followRepoAllById = deviceRepo.findAllByTypeAndIotSpaceIn(2,iotSpaces);

		return followRepoAllById;
	}


	public List<IotSpace> loadSpaceUnderAllDevicesBeforeSpaceIds (Long spaceId) {
		/*
		countupSpaceSubsets是一个函数，传入参数spaceId（以249为例）,得到的结果为：,249,261,258,264,267,373,263,262,259,260,265,266,268,269,374,375

				BEGIN
				DECLARE sTemp VARCHAR(4000);
				DECLARE sTempChild VARCHAR(4000);
				SET sTemp = '';
				SET sTempChild = cast(rootId AS CHAR);    //Cast(字段名 as 转换的类型 )，此句中是将rootId转换为char类型
				WHILE sTempChild IS NOT NULL DO
				SET sTemp = concat(sTemp, ',', sTempChild);

                // FIND_IN_SET(str,strlist)    str 要查询的字符串
				//strlist 字段名 参数以”,”分隔 如 (1,2,6,8)
				//查询字段(strlist)中包含(str)的结果，返回结果为null或记录，例如：mysql> SELECT FIND_IN_SET('b', 'a,b,c,d');
				//-> 2 因为b 在strlist集合中放在2的位置 从1开始
				//select FIND_IN_SET('1', '1'); 返回 就是1 这时候的strlist集合有点特殊 只有一个字符串 其实就是要求前一个字符串 一定要在后一个字符串集合中才返回大于0的数
				//select FIND_IN_SET('2', '1，2'); 返回2
				//select FIND_IN_SET('6', '1'); 返回0

				//SELECT vale1, value2 into Table2 from Table1
				//要求目标表Table2不存在，因为在插入时会自动创建表Table2，并将Table1中指定字段数据复制到Table2中

				SELECT group_concat(id)
				INTO sTempChild
				FROM iot_space
				WHERE find_in_set(parent_id, sTempChild) > 0

		        END WHILE;
				RETURN sTemp;
			    END

		 */
		String sql = "select countupSpaceSubsets ("+spaceId+")";

		String singleResult = em.createNativeQuery(sql).getSingleResult().toString();
		List<IotSpace> ids = Splitter.on(",").splitToList(singleResult).stream().filter(str -> !str.equals("")).map(item -> {
			IotSpace iotSpace = new IotSpace();
			iotSpace.setId(Long.parseLong(item));
			return iotSpace;
		}).collect(Collectors.toList());


		return ids;
	}

	/**
	 * 加载工艺监视下的数据....
	 * @param spaceId
	 * @return
	 */
	public Map loadVisionStationDevices(Long spaceId) {

		//查询空间节点的子节点
		List<IotSpace> stationsDb = iotSpaceRepo.loadStationsObjsByPid(spaceId);
		Map result = new HashMap();

		if (stationsDb.size() == 0) {
			result.put("status", 403);
			result.put("msg", "空间下无配置空间数据");
			return result;
		}
		// 排序
		List<IotSpace> stationsDbResult = stationsDb.stream().sorted(Comparator.comparing(IotSpace::getSort,Comparator.nullsLast(Integer::compareTo))).collect(Collectors.toList());

		// 子孙空间所有挂载的设备
		List<IotDev> spaceDevs = loadSpaceUnderAllConbinedDevices(spaceId);

		if (spaceDevs.size() == 0) {
			result.put("status", 403);
			result.put("msg", "空间下无配置设备数据");
			return result;
		}

		// 排序
		List<Map> datas = new ArrayList<>();
		Map saveMap = new HashMap(1);

		for (int i = 0; i < stationsDbResult.size(); i++) {

			IotSpace curSpace = stationsDbResult.get(i);
			List<IotDev> singleSpaceDevs = spaceDevs.stream().filter(item -> item.getIotSpace().getId().equals(curSpace.getId())).collect(Collectors.toList());
			if (singleSpaceDevs.size() == 0) {
				result.put(curSpace.getName(), Collections.emptyList());
				continue;
			}

			IotDev youKey = singleSpaceDevs.get(0);

			Map handleMap = convertDevToMap(youKey);
			handleMap.put("devParams", youKey.getDevParams());
			handleMap.put("sort", curSpace.getSort());
			handleMap.remove("ctrlProcess");
			handleMap.remove("props");
			handleMap.remove("devParams");
			datas.add(handleMap);


		}

		// 排序

		if (datas.size() > 0) {
			List<String> colss = ((List<Map>) datas.get(0).get("data")).stream().map(item -> item.get("dataType").toString()).collect(Collectors.toList());
			saveMap.put("cols", colss);
		} else {
			saveMap.put("cols", Collections.emptyList());
		}

		saveMap.put("values", datas);

		return saveMap;

	}

	/**
	 * 获取某个 空间下所挂载的空间设备
	 * @param spaceId 这个参数是什么来的
	 * @return
	 */
	public Map loadStationDevices(Long spaceId) {

		//查询空间节点的子节点
		List<IotSpace> stationsDbResult = iotSpaceRepo.loadStationsObjsByPid(spaceId);
		Map result = new HashMap();
		//
		if (stationsDbResult.size() == 0) {
			result.put("status", 403);
			result.put("msg", "空间下无配置空间数据");
			return result;
		}

		List<IotDev> spaceDevs = loadSpaceUnderAllConbinedDevices(spaceId);

		if (spaceDevs.size() == 0) {
			result.put("status", 403);
			result.put("msg", "空间下无配置设备数据");
			return result;
		}

		for (int i = 0; i < stationsDbResult.size(); i++) {

			IotSpace curSpace = stationsDbResult.get(i);
			List<IotDev> singleSpaceDevs = spaceDevs.stream().filter(item -> item.getIotSpace().getParentId().equals(curSpace.getId())).collect(Collectors.toList());
			if (singleSpaceDevs.size() == 0) {
				result.put(curSpace.getName(), Collections.emptyMap());
				continue;
			}

			Map sonMap = new HashMap();
			Map<Integer, List<IotDev>> sonGroupResult = singleSpaceDevs.stream().collect(Collectors.groupingBy(you -> you.getIotSpace().getType()));

			if (sonGroupResult.containsKey(10)) {
				List<IotDev> targetDevs2 = sonGroupResult.get(10);
				List<Map> ctrlList = targetDevs2.stream().map(dev -> {
					Map handleMap = convertDevToMap(dev);
					handleMap.put("devParams", dev.getDevParams());
					handleMap.remove("ctrlProcess");
					handleMap.remove("props");
					return handleMap;
				}).collect(Collectors.toList());
				sonMap.put("ctrl", ctrlList.get(0));

			} else {
				Map zanwei = new HashMap();
				zanwei.put("devParams",Collections.emptyList());
				sonMap.put("ctrl", zanwei);
			}
			if (sonGroupResult.containsKey(11)) {
				List<IotDev> targetDevs = sonGroupResult.get(11);
				List<Map> saveList = targetDevs.stream().map(dev -> convertDevToMap(dev)).collect(Collectors.toList());
				sonMap.put("values", saveList);
				sonMap.put("cols", sonGroupResult.get(11).get(0).getVirtualItems().stream().map(bingo -> bingo.getAlias()).collect(Collectors.toList()));
			} else {
				sonMap.put("values", Collections.emptyList());
				sonMap.put("cols", Collections.emptyList());
			}

			result.put(curSpace.getName(), sonMap);

		}


		return result;

		/*List<IotDev> allDevices = null;
		Map<Long, List<IotDev>> groupingResult = null;
		List<IotSpace> devsInSpaces = new ArrayList<>(16);
		boolean spaceNotChild = true;

		//查询空间节点的子节点
		List<Map> stationsDbResult = iotSpaceRepo.loadStationsObjsByPid(spaceId);
		//空间下只有设备,没有子节点
		IotSpace iotSpaceNotChild = null;
		if (stationsDbResult.size() == 0) {
			spaceNotChild = true;
			iotSpaceNotChild = iotSpaceRepo.getById(spaceId);
			allDevices = deviceRepo.getAllByIotSpace(iotSpaceNotChild);
		} else {
			spaceNotChild = false;
			//机组
			List<IotSpace> handleSpaces = stationsDbResult.stream().map(item -> {
				IotSpace iotSpace = new IotSpace();
				iotSpace.setId(Long.parseLong(item.get("id").toString()));
				return iotSpace;
			}).collect(Collectors.toList());

			//查询空间节点的子节点
			for (IotSpace iotSpace : handleSpaces){
				List<Map> spacesByParentId = iotSpaceRepo.loadStationsObjsByPid(iotSpace.getId());
				spacesByParentId.forEach(item -> {
					IotSpace iotSpace1 = new IotSpace();
					iotSpace1.setId(Long.parseLong(item.get("id").toString()));
					//存取需要返回的空间设备id
					devsInSpaces.add(iotSpace1);
				});
			}
			// 加载第三种设备
			allDevices = deviceRepo.findAllByTypeAndIotSpaceIn( 2, devsInSpaces);
		}


		//分组
		if (allDevices.size() > 0) {
			groupingResult = allDevices.stream().collect(Collectors.groupingBy(item -> item.getIotSpace().getParentId()));
			for (Map.Entry<Long,List<IotDev>> map: groupingResult.entrySet()) {
				Map bigMap = new HashMap();
				List<Map> hellMap = new ArrayList<>();
				List<IotDev> iotDevs = map.getValue();
				boolean hasCtrl = true;
				if (iotDevs.size() > 0) {
					boolean quitFor = false;
					for (int i = 0; i < iotDevs.size(); i++){
						// 获取控制器设备
						if (iotDevs.get(i).getIotSpace().getType() == 10) {
							iotDevs.add(0, iotDevs.get(i));
							iotDevs.remove(i + 1);
							hasCtrl = true;
							break;
						}else{
							// 没控制器
							hasCtrl = false;
						}
					}
				}

				for (int i = 0; i < iotDevs.size(); i++) {
					IotDev curDev = iotDevs.get(i);
					Map simpleRealData = simpleRealData(curDev.getId());
					Map newMapIot = new HashMap();
					newMapIot.put("devId", curDev.getId());
					newMapIot.put("devName", curDev.getName());
					newMapIot.put("data", simpleRealData.get("data"));
					newMapIot.put("props", getProLists(curDev));
						bigMap.put("ctrl", newMapIot);
					if (hasCtrl && i ==0) {
						// 处理控制器
						newMapIot.put("devParams", curDev.getDevParams());
						continue;
					}
					if (hasCtrl && i == 1) {
						bigMap.put("cols", curDev.getVirtualItems().stream().map(item -> item.getName()).collect(Collectors.toList()));
					}
					if (!hasCtrl && i == 0) {
						bigMap.put("cols", curDev.getVirtualItems().stream().map(item -> item.getName()).collect(Collectors.toList()));
					}
					newMapIot.put("ctrlProcess", curDev.getCtrlProcesses());
					hellMap.add(newMapIot);
				}

				bigMap.put("values", hellMap);

				if (spaceNotChild) {
					result.put(iotSpaceNotChild.getName(), bigMap);
				} else {
					stationsDbResult.forEach(item -> {
						if (item.get("id").toString().equals(map.getKey().toString())){
							result.put(item.get("name"), bigMap);
						}
					});
				}
			}
		}

		return result;*/
	}

	public Map convertDevToMap(IotDev dev) {

			Map simpleRealData = simpleRealData(dev.getId());
			Map newMapIot = new HashMap();
			newMapIot.put("devId", dev.getId());
			newMapIot.put("pic", dev.getPic());
			newMapIot.put("devName", dev.getName());
			newMapIot.put("data", simpleRealData.get("data"));
			newMapIot.put("props", getProLists(dev));
			newMapIot.put("ctrlProcess", dev.getCtrlProcesses());

			return newMapIot;
	}

	public Map getDevNumberBySpaceId(Long spaceId){

		JSONObject result = new JSONObject();
		Map dbResult = loadStationDevices(spaceId);
		Iterator<Map.Entry<String,Map>> iterator = dbResult.entrySet().iterator();
		while (iterator.hasNext()){
			Map.Entry<String,Map> mapEntry = iterator.next();
			Map map = mapEntry.getValue();
			List list = (List) map.get("values");
			result.put(mapEntry.getKey(), list.size());
		}

		return result;
	}

	/**
	 * 供js调用，查询工艺控制下的 设备 数量
	 * @param spaceId 前端只能传入站房ID？
	 * @return
	 */
	public Map getStationSpaceDevices(Long spaceId) {
		Map result = Maps.newHashMap();
		List<IotSpace> iotSpaces = iotSpaceRepo.loadStationsObjsByPid(spaceId);
		if (iotSpaces.size() == 0) {
			return result;
		}
		// 查找工艺控制的菜单101
		Optional<IotSpace> findResult = iotSpaces.stream().filter(item -> item.getType().equals(101)).findAny();
		findResult.ifPresent(consumer -> {
			// 查找工艺控制下的 菜单
			List<IotSpace> spaces2 = iotSpaceRepo.loadStationsObjsByPid(consumer.getId());
			if (spaces2.size() > 0) {
				// 获取工艺控制的第一个菜单，定死为 xx机房的数据
				IotSpace curSpace = spaces2.get(0);
				// 获取 xx机房下，挂在的所有组合设备，自动归类的结果
				Map dbResult = loadStationDevices(curSpace.getId());
				// 业务知识：1. 空压机包含：螺杆机、离心机  2. 干燥机包含：吸干机、冷干机
				// 其他的为都不归类。所以，这里遇到空压机，干燥机，要拆分统计
				// 插入 另类处理 逻辑 start 适当时候不需要可删除
				if (dbResult.containsKey("空压机")) {

					Map airPressDatas = (Map) dbResult.get("空压机");
					if (!airPressDatas.isEmpty()) {
						// 离心机
						List<Map> air1 = Lists.newArrayList();
						// 螺杆机
						List<Map> air2 = Lists.newArrayList();

						// 获取到设备数据
						List<Map> detailDatas = (List<Map>) airPressDatas.get("values");
						System.out.println("Adfsadfasdfasdfd:" + detailDatas);
						for (int i = 0; i < detailDatas.size(); i++) {
							Map curMap = detailDatas.get(i);
							String devName = curMap.get("devName").toString();
							if (devName.indexOf("离心机") > -1) {
								air1.add(curMap);
								continue;
							}
							if (devName.indexOf("螺杆机") > -1) {
								air2.add(curMap);
								continue;
							}
						}

						Map saveMap1 = Maps.newHashMap();
						Map saveMap2 = Maps.newHashMap();

						saveMap1.put("values", air1);
						saveMap2.put("values", air2);


						dbResult.put("离心机", saveMap1);
						dbResult.put("螺杆机", saveMap2);
						dbResult.remove("空压机");
					}
				}

				if (dbResult.containsKey("干燥机")) {

					Map airPressDatass = (Map) dbResult.get("干燥机");

					if (!airPressDatass.isEmpty()) {
						// 冷干机
						List<Map> cool1 = Lists.newArrayList();
						// 吸干机
						List<Map> cool2 = Lists.newArrayList();

						// 获取到设备的数据
						List<Map> detailDatass = (List<Map>) airPressDatass.get("values");

						for (int i = 0; i < detailDatass.size(); i++) {
							Map curMap2 = detailDatass.get(i);
							String devName = curMap2.get("devName").toString();
							if (devName.indexOf("冷干机") > -1) {
								cool1.add(curMap2);
								continue;
							}
							if (devName.indexOf("吸干机") > -1) {
								cool2.add(curMap2);
								continue;
							}
						}

						Map saveMap11 = Maps.newHashMap();
						Map saveMap22 = Maps.newHashMap();

						saveMap11.put("values", cool1);
						saveMap22.put("values", cool2);


						dbResult.put("冷干机", saveMap11);
						dbResult.put("吸干机", saveMap22);

						dbResult.remove("干燥机");
					}
				}
				if (dbResult.containsKey("用能车间")) {
					result.put("车间详情", dbResult.get("用能车间"));
				}
				// 插入 另类处理 逻辑 end 适当时候不需要可删除
				Iterator<Map.Entry<String, Map>> iterator = dbResult.entrySet().iterator();
				while (iterator.hasNext()) {
					Map.Entry<String, Map> mapEntry = iterator.next();

					if (mapEntry.getValue().isEmpty()) {
						result.put(mapEntry.getKey(), 0);
					} else {
						// 兼容小程序 空的东西
						Map map = mapEntry.getValue();
						List list = (List) map.get("values");
						result.put(mapEntry.getKey(), list.size());
					}
				}
			}
		});

		return result;
	}

	/**
	 * 查询站房设备数据
	 * @param spaceId
	 * @return
	 */
	public Map loadStationDevices (Long spaceId, List<String> names) {

		/*List<IotSpace> stationsDbResult = iotSpaceRepo.loadStationsObjsByPid(spaceId);
		if (stationsDbResult.size() == 0) {
			return Collections.emptyMap();
		}

		Map<String, List<IotDev>> groupingResult = null;

		List<IotSpace> handleSpaces = stationsDbResult.stream().map(item -> {
			IotSpace iotSpace = new IotSpace();
			iotSpace.setId(Long.parseLong(item.get("id").toString()));
			return iotSpace;
		}).collect(Collectors.toList());

		// 加载第三种设备
		List<IotDev> allDevices = deviceRepo.findAllByTypeAndIotSpaceIn( 2, handleSpaces);

		Map finalResult = new HashMap();

		//分组
		if (allDevices.size() > 0) {
			groupingResult = allDevices.stream().collect(Collectors.groupingBy(item -> item.getIotSpace().getName()));
			for (Map.Entry<String,List<IotDev>> map: groupingResult.entrySet()) {
				Map bigMap = new HashMap();
				List<Map> hellMap = new ArrayList<>();
				List<IotDev> iotDevs = map.getValue();
				boolean hasCtrl = true;
				if (iotDevs.size() > 0) {
					for (int i = 0; i < iotDevs.size(); i++){
						if (iotDevs.get(i).getName().indexOf("控制器") > -1) {
							iotDevs.add(0, iotDevs.get(i));
							iotDevs.remove(i + 1);
							hasCtrl = true;
							break;
						}else{
							// 没控制器
							hasCtrl = false;
						}
					}
				}
//				bigMap.put("devs", iotDevs);

				for (int i = 0; i < iotDevs.size(); i++) {
					IotDev curDev = iotDevs.get(i);
					Map simpleRealData = simpleRealData(curDev.getId());
					Map newMapIot = new HashMap();
					newMapIot.put("devId", curDev.getId());
					newMapIot.put("devName", curDev.getName());
					newMapIot.put("data", simpleRealData.get("data"));
					newMapIot.put("props", getProLists(curDev));
					if (hasCtrl && i ==0) {
						// 处理控制器
						newMapIot.put("devParams", curDev.getDevParams());
						bigMap.put("ctrl", newMapIot);
						continue;
					}
					if (hasCtrl && i == 1) {
						bigMap.put("cols", curDev.getVirtualItems().stream().map(item -> item.getName()).collect(Collectors.toList()));
					}
					if (!hasCtrl && i == 0) {
						bigMap.put("cols", curDev.getVirtualItems().stream().map(item -> item.getName()).collect(Collectors.toList()));
					}
					newMapIot.put("ctrlProcess", curDev.getCtrlProcesses());
					hellMap.add(newMapIot);
				}

				bigMap.put("values", hellMap);
//				bigMap.put("ddd", allDevices);
				finalResult.put(map.getKey(), bigMap);
			}
		}

//		return groupingResult;
		return finalResult;*/

		return null;
	}

	public List<String> getProLists(IotDev dev) {

		List<String> result = null;

		System.out.println(dev);

		if (dev.getType() == 0) {
			result = dev.getIotDevType().getIotCollItems().stream().filter(pop -> !"".equals(pop.getType()) && pop.getType() != null && !pop.getType().equals("开关量")).map(item -> item.getType()).distinct().collect(Collectors.toList());
		} else {
			result = dev.getVirtualItems().stream().filter(pop -> !"".equals(pop.getType()) && pop.getType() != null && !pop.getType().equals("开关量")).map(hell -> hell.getType()).distinct().collect(Collectors.toList());
		}

		return result;
	}

	/**
	 * 导入数据
	 * @param models
	 * @return
	 */
	@Transactional(rollbackOn = Exception.class)
	public int importDatas (List<IotDevImportModel> models) {

		if (models.size() == 0) {
			return 0;
		}

		List<IotDev> insertObjs  = models.stream()
		                             .filter(item -> item.getCommAddr() != null && !item.getIotDevType().equals(0)
				                                             && item.getName() != null && !item.getIotSpace().equals(0) && !item.getReadInterval().equals(0))
		                             .map(dev -> {
			                             IotDev iotDev = new IotDev();
			                             iotDev.setName(dev.getName());
			                             iotDev.setReadInterval(dev.getReadInterval());
			                             iotDev.setCommAddr(dev.getCommAddr());
			                             IotSpace space = new IotSpace();
			                             space.setId(dev.getIotSpace());
			                             iotDev.setIotSpace(space);
			                             IotDevType devType = new IotDevType();
			                             devType.setId(dev.getIotDevType());
			                             iotDev.setIotDevType(devType);
			                             return iotDev;
		                             }).collect(Collectors.toList());

		List<IotDev> iotDevs = deviceRepo.saveAll(insertObjs);

		return iotDevs.size();
	}


	/**
	 * 查询单个设备数据近段时间数据
	 * @param id 设备id
	 * @param timeLevel 为统计粒度:1--秒，2--分，3--时，4--天，5--月，6--年
	 * @param dataType 数据类型
	 * @return
	 */
	public IotDev realData (Long id,  Integer timeLevel, String dataType,String startTime,String endTime) {

		SqlHelper sqlHelper = SqlHelper.getBySource(this.dataSource);

		IotDev dev = deviceRepo.getById(id);

		if (dev == null) {
			return null;
		}

		//List<IotCollItem> colls = dev.getIotDevType().getIotCollItems();

		List<Map<String, Object>> dbDataValues = Collections.EMPTY_LIST;
		try {
			dbDataValues = sqlHelper.queryList("select dev_id, " +
					" dvalue, DATE_FORMAT(the_time,'"+UServ.map4TimeLevel2SqlFmt(timeLevel)+"') as theTime " +
					" from iot_dev_data_win win " +
					" where 1=1 "
					+ " and dev_id=" + id
					+ " and data_type='" + dataType + "'"
					+" and STR_TO_DATE(the_time,'%Y-%m-%d %H:%i:%s') between STR_TO_DATE('"+startTime+"','%Y-%m-%d %H:%i:%s')"
					+"  and STR_TO_DATE('"+endTime+"','%Y-%m-%d %H:%i:%s')"
					+ " group by theTime "
					+ " ORDER BY  the_time ");
		} catch (SQLException e) {
			e.printStackTrace();
		}

		LinkedList<Object> itemDatas = new LinkedList<Object>();


			IotCollItemData data = new IotCollItemData(dataType, "");
			HashMap<String, Object> datas = new HashMap<String,Object>();
			data.setValue(datas);

			itemDatas.add(data);

			LinkedList<Object> theTimes = new LinkedList<Object>();
			LinkedList<Object> values = new LinkedList<Object>();
			datas.put("theTimes", theTimes);
			datas.put("values", values);

			for (Map<String, Object> dbItem : dbDataValues) {
				try {
					Object value = dbItem.get("dvalue");
					Object theTime = dbItem.get("theTime");

					value = new DecimalFormat("0.00").format(value);

					values.add(value);
					theTimes.add(theTime);
				} catch (Exception e) {
					log.info("getDataError. dataType=" + dataType + " devId" + id );
				}

			}

		dev.setIotCollItemDatas(itemDatas);

		return dev;
	}
    /*
    id 为设备id
    dayCnt 需要显示的天数
    timeLevel为统计粒度:1--秒，2--分，3--时，4--天，5--月，6--年
    dataType 数据类型
     */
    public IotDev getDataByRang (Long id, String startDate,String endDate, Integer timeLevel, String dataType) {

        SqlHelper sqlHelper = SqlHelper.getBySource(this.dataSource);

        IotDev dev = deviceRepo.getById(id);

        if (dev == null) {
            return null;
        }

        List<IotCollItem> colls = dev.getIotDevType().getIotCollItems();

        List<Map<String, Object>> dbDataValues = Collections.EMPTY_LIST;
        try {
            dbDataValues = sqlHelper.queryList("select dev_id, " +
                    " dvalue, DATE_FORMAT(the_time,'"+UServ.map4TimeLevel2SqlFmt(timeLevel)+"') as theTime " +
                    " from iot_dev_data_win win " +
                    " where 1=1 "
                    + " and dev_id=" + id
                    + " and data_type='" + dataType + "'"
                    +" and the_time between "+startDate+" and "+endDate+" ) "
                    + " group by theTime "
                    + " ORDER BY  the_time ");
        } catch (SQLException e) {
            e.printStackTrace();
        }
        LinkedList<Object> itemDatas = new LinkedList<Object>();
        for (IotCollItem item : colls) {

            if (!dataType.equals(item.getName())) {
                continue;
            }

            IotCollItemData data = new IotCollItemData(item);
            HashMap<String, Object> datas = new HashMap<String,Object>();
            data.setValue(datas);

            itemDatas.add(data);

            LinkedList<Object> theTimes = new LinkedList<Object>();
            LinkedList<Object> values = new LinkedList<Object>();
            datas.put("theTimes", theTimes);
            datas.put("values", values);

            for (Map<String, Object> dbItem : dbDataValues) {
                try {
                    Object value = dbItem.get("dvalue");
                    Object theTime = dbItem.get("theTime");

                    value = new DecimalFormat("0.00").format(value);

                    values.add(value);
                    theTimes.add(theTime);
                } catch (Exception e) {
                    log.info("getDataError. dataType=" + dataType + " devId" + id );
                }

            }
        }
        dev.setIotCollItemDatas(itemDatas);

        return dev;
    }

	public Map simpleRealData (Long id) {

		IotDev deviceRepoById = null;
		try {
			// 从缓存获取设置
			deviceRepoById = (IotDev) CacheUtils.guavaCacheFactory.getIfPresent(String.valueOf(id));
		} catch (Exception e) {
			e.printStackTrace();
		}
		// 如果缓存没有没有数据从数据库获取
		if (deviceRepoById == null) {
			deviceRepoById = deviceRepo.getById(id);
			// 把设置数据保存到缓存中
			if (ObjectUtils.allNotNull(deviceRepoById)) {
				CacheUtils.guavaCacheFactory.put(String.valueOf(id), deviceRepoById);
			}else{
				return null;
			}
		}

		SqlHelper sqlHelper = SqlHelper.getBySource(this.dataSource);

		//获取设备属性
		List<String> dateTypes = new ArrayList<>(32);
		List<String> dateTypeByAlias = new ArrayList<>(32);
		List<Long> dateTypesId = new ArrayList<>(32);
		if (deviceRepoById != null){
			if (deviceRepoById.getType() == 0){
				IotDevType iotDevType = deviceRepoById.getIotDevType();
				if (iotDevType != null){
					List<IotCollItem> iotCollItems = iotDevType.getIotCollItems();
					if (iotCollItems != null){
						for (IotCollItem iotCollItem : iotCollItems){
							dateTypes.add(iotCollItem.getName());
						}
					}
				}
			}else{
				List<IotVirtualItem> virtualItems = deviceRepoById.getVirtualItems();
				if (virtualItems != null){
					for (IotVirtualItem iotVirtualItem : virtualItems){
						// 优先提取 别名，别名没有取名字
						dateTypes.add(iotVirtualItem.getName());
						dateTypeByAlias.add(iotVirtualItem.getAlias());
						dateTypesId.add(iotVirtualItem.getId());
					}
				}
			}
		}
		//请求数据，循环每个属性
		Map result = new HashMap<>(16);
		List<Map<String, Object>> maps = new ArrayList<Map<String, Object>>(16);

		/**
		 * 全部属性一起查询
		 */
		try {
			String sql = "SELECT * FROM `iot_dev_cur_data_win`\n" +
					"where \n" +
					"dev_id = "+ id +" AND\n" +
					"uptime BETWEEN DATE_ADD(NOW(), INTERVAL -6 MINUTE) AND NOW();";
			List<Map<String, Object>> mapList = sqlHelper.queryList(sql);

			//处理数据
			for (String dataType : dateTypes){
				// 获取属性数组下标
				int i = dateTypes.indexOf(dataType);
				int mapsSize = maps.size();
				for (Map<String, Object> map : mapList){

					String dataTypeBySQL = map.get("data_type") != null ? map.get("data_type").toString() : null;
					if (dataType.equals(dataTypeBySQL)){
						Map<String, Object> newMap = new HashMap<>();
						newMap.put("value", map.get("dvalue"));
						// 排除非空为 null 字符串的情况
						newMap.put("unit", "null".equals(map.get("unit").toString())? "" : map.get("unit"));
						newMap.put("dataType", dataType);
						// 塞进去别名-- 前端显示
						newMap.put("alias", dateTypeByAlias.get(i));
						newMap.put("id", dateTypesId.get(i));
						maps.add(newMap);
						continue;
					}
				}
				//判断maps是否有增加
				if (mapsSize == maps.size()){
					Map<String, Object> newMap = new HashMap<>();
					newMap.put("value", "N/A");
					newMap.put("unit", "");
					newMap.put("dataType", dataType);
					newMap.put("alias", dateTypeByAlias.get(i));
					newMap.put("id", dateTypesId.get(i));
					maps.add(newMap);
				}
			}

		} catch (SQLException e) {
			e.printStackTrace();
		}
		Map proValue = new HashMap();
		proValue.put("data", maps);
		proValue.put("devId", id);
		proValue.put("devName", deviceRepoById.getName());
//		result.put("devId", id);
//		result.put("proValues", proValue);
		return proValue;
	}
	/**
	 * 组态 数据 实时数据请求
	 * @param uuid
	 */
	public List<Map> sysImgRealData (String uuid) {

		List<IotConfigDevice> dbResultP= configDeviceRepo.findAllByUuid(uuid);
		List<Map> storeResult = Lists.newArrayList();
		List<Map> storeResult2 = Lists.newArrayList();
		if (dbResultP.size() > 0) {
			dbResultP.forEach(item -> {   //遍历操作
				List<String> propertiesList = Splitter.on("_").splitToList(item.getProperties());
				if (propertiesList.size()>0) {
					for (int i = 0; i < propertiesList.size(); i++) {
						//拆分属性 于别名
						List<String> proSplits = Splitter.on("|").splitToList(propertiesList.get(i));
						//拆分属性类别
						List<String> proTypeSplits = Splitter.on("-").splitToList(proSplits.get(0));
						Map findRealData = configDeviceRepo.loadRealTimeData(item.getDevId(), proTypeSplits.get(0));
						// java.lang.UnsupportedOperationException: A TupleBackedMap cannot be modified?????????????
						Map changeNotTupleMap = Maps.newHashMap();
						// 保留三位小数，频率除以10
						String kkName = proSplits.size() > 1 ? proSplits.get(1) : proTypeSplits.get(0);
						changeNotTupleMap.put("keyName", kkName);
						if (kkName.indexOf("频率") > -1) {   //indexOf（Sting str）该子字符串在该字符串中第一次出现处的索引
							if(victures.equals("true")){
								changeNotTupleMap.put("value",new DecimalFormat("0.00").format(Math.random()*300+50));
							}else{
								changeNotTupleMap.put("value", findRealData.get("value") == null ? "N/A" :
										new BigDecimal(findRealData.get("value").toString()).divide(new BigDecimal(10), 0,BigDecimal.ROUND_HALF_UP)
												.setScale(0, RoundingMode.HALF_UP).doubleValue());
							}
						} else {
							if(victures.equals("true")){
								changeNotTupleMap.put("value",new BigDecimal(Math.random()*455+90).setScale(3, RoundingMode.HALF_UP).doubleValue());
							}else {
								changeNotTupleMap.put("value", findRealData.get("value") == null ? "N/A" :
										new BigDecimal(findRealData.get("value").toString())
												.setScale(3, RoundingMode.HALF_UP).doubleValue());
							}
						}
						changeNotTupleMap.put("unit", findRealData.get("unit"));
						if (proTypeSplits.size() > 1) {
							changeNotTupleMap.put("type", proTypeSplits.get(1));
						}
						storeResult.add(changeNotTupleMap);
					}
				}
			});
		}
		if (storeResult.size()>0) {
			// 优先显示属性名称
			List<String> priorityList = Stream.of("P","T","进水温度", "进水压力","回水温度","运行时间").collect(Collectors.toList());
			List<String> hasList= storeResult.stream().map(item -> item.get("keyName").toString()).collect(
					Collectors.toList());

			List<String> mixStardOrderList = Stream.concat(priorityList.stream(), hasList.stream().filter(item -> !priorityList.contains(item))).collect(
					Collectors.toList());
			// 排序数据，指定优先数据
			storeResult2 = storeResult.stream().sorted(new Comparator<Map>() {

				Ordering ordering = Ordering.explicit(mixStardOrderList);

				@Override
				public int compare (Map o1, Map o2) {
					if (mixStardOrderList.contains(o1.get("keyName").toString()) && mixStardOrderList.contains(o2.get("keyName").toString())) {
						return ordering.nullsFirst().compare(o1.get("keyName").toString(), o2.get("keyName").toString());
					} else {
						return 0;
					}
				}
			}).collect(Collectors.toList());
		}
		return storeResult2;
	}

	/**
	 * 单个属性 数据
	 * @param devId
	 * @param dataType
	 * @return
	 */
	public Map singlePropertyRealData(Long devId,String dataType){

		Map changeNotTupleMap = Maps.newHashMap();

		Map findRealData = configDeviceRepo.loadRealTimeData(devId, dataType);
		if("true".equals("victures")){
			changeNotTupleMap.put("value", new DecimalFormat("0.00").format(Math.random()*100+50));   /*mkAlter  3月19日*/
		}else{
			// 保留两位小数
			changeNotTupleMap.put("value", findRealData.get("value") == null ? "N/A" :
					new BigDecimal(findRealData.get("value").toString())
							.setScale(2, RoundingMode.HALF_UP).doubleValue());
		}
		changeNotTupleMap.put("keyName", dataType);
		changeNotTupleMap.put("unit", findRealData.get("unit") == null ? "": findRealData.get("unit"));

		return changeNotTupleMap;
	}

	/**
	 * 查找 属性的 分页数据
	 * @param pageable
	 * @param map
	 * @return
	 */
	public PageInfo findCollItem (Pageable pageable, Map map) {
		PageHelper.startPage(pageable.getPageNumber(), pageable.getPageSize());
		int type = Integer.parseInt(map.get("type").toString());
		List<Map> dbResult = null;
		if (type == 0) {
			dbResult = devMapper.loadAllCollItems(map);
		} else {
			dbResult = devMapper.loadAllVirtualCollItems(map);
		}
		PageInfo pageInfo = new PageInfo(dbResult);
		return pageInfo;
	}

	/**
	 * 查询 iot_dev_data_win 数据  插入数据
	 * @param pageable
	 * @param map
	 * @return
	 */
	public Page<Map> loadDataEntry (Pageable pageable, Map map) {

		String sTime = "";
		String eTime = "";
		// 如果没有传入 时间参数，则默认使用一个大范围的时间范围
		if (map.get("sTime") == null) {
			sTime = "2000-01-01 01:01:01";
		}else {
			if ("".equals(map.get("sTime").toString())) {
				sTime = "2000-01-01 01:01:01";
			} else {
				sTime = map.get("sTime").toString();
			}
		}
		if(map.get("eTime") == null) {
			eTime = DateTime.now().toString("yyyy-MM-dd HH:mm:ss");
		}else {
			if ("".equals(map.get("eTime").toString())) {
				eTime = DateTime.now().toString("yyyy-MM-dd HH:mm:ss");
			}else {
				eTime = map.get("eTime").toString();
			}
		}

		Page<Map> pageInfo = deviceRepo.loadDataEntry(Long.parseLong(map.get("devId").toString()), sTime, eTime, map.get("selectProp").toString(), pageable);

		return pageInfo;
	}


	@Transactional(rollbackOn = Exception.class)
	public int saveDataLogs(Map map){

		Long devId = Long.parseLong(map.get("devId").toString());
		String theTime = map.get("theTime").toString();
		String proName = map.get("propName").toString();
//		String unit = map.get("unit").toString();
		Double dvalue = Double.parseDouble(map.get("avalue").toString());

        String sql = "insert into iot_dev_data_win(dev_id, the_time, data_type, dvalue,order_num) values(" + devId + ", \'" + theTime + "\', \'" + proName + "\', " + dvalue + ", 1)";

        int effectResult = em.createNativeQuery(sql).executeUpdate();

		return effectResult;
	}

	@Transactional(rollbackOn = Exception.class)
	public void delDataLogs(Long[] ids){
        deviceRepo.delDataLogs(ids);
	}

	@Transactional(rollbackOn = Exception.class)
	public int updateDeviceParams(List<IotDevParams> datas) {
		int flag = 0;
		for (int i = 0; i < datas.size(); i++) {
			IotDevParams params = datas.get(i);
			int flagResult = deviceRepo.updateDeviceParams(params.getId(), params.getValue());
			flag += flagResult;
		}
		return flag;
	}

	/**
	 * 保存数据
	 * @param map
	 * @return
	 */
	@Transactional(rollbackOn = Exception.class)
	public int updateDataLogs(Map map){

		Long id = Long.parseLong(map.get("id").toString());
		String theTime = map.get("theTime").toString();
		Double dvalue = Double.parseDouble(map.get("avalue").toString());

		int effectResult = deviceRepo.updateDataLogs(id, theTime, dvalue);

		return effectResult;
	}


	/**
	 * 获取配置值
	 * @param devId
	 * @return
	 */
	public List<Map> loadDefaultValues(Long devId, String name){

		String sql = "select * from iot_dev_prop where dev_id = " + devId;
		if(!"".equals(name)) {
			sql = sql + " and name = '" + name + "'";
		}


		Query nativeQuery = em.createNativeQuery(sql);
		nativeQuery.unwrap(NativeQueryImpl.class).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);


		return nativeQuery.getResultList();
	}

	/*
	id 为设备id
	dayCnt 需要显示的天数
	timeLevel为统计粒度:1--秒，2--分，3--时，4--天，5--月，6--年
	 */
	public IotDev realData2 (Long id, Integer dayCnt, Integer timeLevel) {

		SqlHelper sqlHelper = SqlHelper.getBySource(this.dataSource);

		IotDev dev = deviceRepo.getById(id);

		if (dev == null) {
			return null;
		}

		List<IotCollItem> colls = dev.getIotDevType().getIotCollItems();

		Map<Object, Map<String, Object>> dbData = Collections.EMPTY_MAP;
		try {
			dbData = sqlHelper.query("select data_type,dev_id, " +
					" dvalue, DATE_FORMAT(the_time,'%Y-%m-%d %H:%i') as theTime " +
					" from iot_dev_data_win win " +
					" where 1=1 "
					+ " and dev_id=" + id
					+" and the_time>date_sub(now(), interval "+dayCnt+" day) " +
					" group by theTime "
					+ " ORDER BY data_type, the_time ");
		} catch (SQLException e) {
			e.printStackTrace();
		}

		Collection<Map<String, Object>> dbDataValues = dbData.values();

		LinkedList<Object> itemDatas = new LinkedList<Object>();
		for (IotCollItem item : colls) {
			IotCollItemData data = new IotCollItemData(item);
			LinkedList<Object> datas = new LinkedList<Object>();
			data.setValue(datas);
			for (Map<String, Object> dbItem : dbDataValues) {
				String dataType = (String) dbItem.get("data_type");
				Object value = dbItem.get("dvalue");
				Object theTime = dbItem.get("theTime");
				if (theTime != null) {
					theTime = U.DF.format((Date) theTime);
				}

				Map<String, Object> dataMap = new HashMap<String, Object>();

				dataMap.put("theTime", theTime);
				dataMap.put("value", value);

				value = new DecimalFormat("0.00").format(value);

				if (dataType.equals(item.getName())) {
					//					data.setValue(value);
					datas.add(dataMap);
				}
			}
			itemDatas.add(data);
		}

		dev.setIotCollItemDatas(itemDatas);

		return dev;
	}



	private Random rd = new Random();

    public Map<String, Object> curSysLineData(String spaceCode, String eneryType, Integer dataCnt) {

		Map<String, Object> result = new HashMap<String, Object>();
		List<Object> datas = new ArrayList<Object>();

		SqlHelper sqlHelper = SqlHelper.getBySource(this.dataSource);

		result.put("spaceCode", spaceCode);
		result.put("eneryType", eneryType);

		result.put("datas", datas);


        try {
            List<Map<String, Object>> datasInDbList = sqlHelper.queryList("select forder, eneryType, itemName, dev_id, data_type1, data_type2 " +
                    " from tmp_zz_sys " +
                    " where 1=1 " +
                    " and eneryType='" + eneryType + "'" +
                    " and spaceCode='" + spaceCode + "'" +
                    " order by forder ");

            for(Map<String, Object> itemInDb : datasInDbList){
                Map<String, Object> item = new HashMap<String, Object>();

//                Double data1 = rd.nextDouble()*1000.0;
//                Double data2 = rd.nextDouble()*1000.0 * 100;

                String field = itemInDb.get("itemName").toString();
                item.put("name",field);
                item.put("instant",null);
                item.put("total",null);

                if(null != itemInDb.get("dev_id") && null != itemInDb.get("data_type1") ){
//                    Integer devId = (Integer)itemInDb.get("dev_id");
                    String dataType1 = (String)itemInDb.get("data_type1");
                    Map<String, Object> curValue = curDevDataHasType(Long.parseLong(itemInDb.get("dev_id").toString()), dataType1);
                    item.put("instant",curValue.get("dvalue"));
                }
                if(null != itemInDb.get("dev_id") && null != itemInDb.get("data_type2") ){
//                    Integer devId = (Integer)itemInDb.get("dev_id");
                    String dataType2 = (String)itemInDb.get("data_type2");
                    Map<String, Object> curValue = curDevDataHasType(Long.parseLong(itemInDb.get("dev_id").toString()), dataType2);
                    item.put("total",curValue.get("dvalue"));
                }

                datas.add(item);

            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
//        for(int i = 1; i <= dataCnt; ++i){
//			double data1 = rd.nextDouble()*1000.0;
//			double data2 = rd.nextDouble()*1000.0 * 100;
//
//			String field = "field" + i;
//
//			Map<String, Object> item = new HashMap<String, Object>();
//
//			//[{name:'file01',instant:12121,total:232312}，{name:'file02',instant:12121,total:232312}]
//
//			item.put("name",field);
//			item.put("instant",data1);
//			item.put("total",data2);
//
//			datas.add(item);
//		}

		return result;
    }


	public Map<Object,Map<String,Object>> getVirDevInfo(Long id) {

		Map<Object,Map<String,Object>> result = new HashMap<Object,Map<String,Object>>();

		result = this.curDataJustData(id);


		return result;
	}

	public Map<Object,Map<String,Object>> curDataJustData(Long id) {
    	SqlHelper sqlHelper = SqlHelper.getBySource(this.dataSource);


		Map<Object,Map<String,Object>> dbData = Collections.EMPTY_MAP;
		try {
			dbData = sqlHelper.query("select data_type dataType,dev_id devId, dvalue from iot_dev_cur_data_win win where 1=1 " +
					" and dev_id=" + id +
					""
			);
		} catch (SQLException e) {
			e.printStackTrace();
		}

		return dbData;
	}

	public Integer cmdDev(Long id, String cmd,String param){
    	Integer resultCode = 1;

		SqlHelper sqlHelper = SqlHelper.getBySource(this.dataSource);

		try {
			sqlHelper.update("insert into iot_dev_cmd_log(cmd_time,dev_id,cmd,param)" +
					"value(now()," +
					" "+id+"," +
					" '"+cmd+"'," +
					" '"+param+"')");
		} catch (SQLException e) {
			e.printStackTrace();
			resultCode = 2;
		}

		return resultCode;
	}

	public Map <String,Object> getAdminMeasureTreeData(String spaceCode, String eneryType){

		Map<String, Object> result = new HashMap<String,Object>();

		List<Map<String, Object>> levelList = new ArrayList<Map<String, Object>>(5);

		Map<String, Object> level1 = new HashMap<String,Object>();
		Map<String, Object> level2 = new HashMap<String,Object>();
		Map<String, Object> level3 = new HashMap<String,Object>();
		Map<String, Object> level4 = new HashMap<String,Object>();
		Map<String, Object> level5 = new HashMap<String,Object>();

		level1.put("column","企业");
		level2.put("column","工厂");
		level3.put("column","车间");
		level4.put("column","线体");
		level5.put("column","设备");

		levelList.add(level1);
		levelList.add(level2);
		levelList.add(level3);
		levelList.add(level4);
		levelList.add(level5);

		List<Map<String, Object>> subLevel1 = new ArrayList<Map<String, Object>>(2);
		List<Map<String, Object>> subLevel2 = new ArrayList<Map<String, Object>>(2);
		List<Map<String, Object>> subLevel3 = new ArrayList<Map<String, Object>>(2);
		List<Map<String, Object>> subLevel4 = new ArrayList<Map<String, Object>>(2);
		List<Map<String, Object>> subLevel5 = new ArrayList<Map<String, Object>>(2);

		level1.put("list",subLevel1);
		level2.put("list",subLevel2);
		level3.put("list",subLevel3);
		level4.put("list",subLevel4);
		level5.put("list",subLevel5);
		//{title: '东风日产', id: 'dfbt', value: 34565, unit: 'm³', hasChildNodes: true, fatherNode: '', isShow: false, isShowChild: false}
		Map<String, Object> subLevel1Item1 = new HashMap<String,Object>();
		subLevel1Item1.put("title","东风日产");
		subLevel1Item1.put("id","dfbt");
		subLevel1Item1.put("value",34565);
		subLevel1Item1.put("unit","m³");
		subLevel1Item1.put("hasChildNodes",true);
		subLevel1Item1.put("fatherNode","");
		subLevel1Item1.put("isShow",false);
		subLevel1Item1.put("isShowChild",false);
		subLevel1.add(subLevel1Item1);
//		{title: '郑州工厂', id: 'zz', value: 12345, unit: 'm³', hasChildNodes: true, fatherNode: 'dfbt', isShow: false, isShowChild: false},
//		{title: '武汉工厂', id: 'wh', value: 34445, unit: 'm³', hasChildNodes: true, fatherNode: 'dfbt', isShow: false, isShowChild: false}
		Map<String, Object> subLevel2Item1 = new HashMap<String,Object>();
		subLevel2Item1.put("title","郑州工厂");
		subLevel2Item1.put("id","zz");
		subLevel2Item1.put("value",12345);
		subLevel2Item1.put("unit","m³");
		subLevel2Item1.put("hasChildNodes",true);
		subLevel2Item1.put("fatherNode","dfbt");
		subLevel2Item1.put("isShow",false);
		subLevel2Item1.put("isShowChild",false);
		Map<String, Object> subLevel2Item2 = new HashMap<String,Object>();
		subLevel2Item2.put("title","武汉工厂");
		subLevel2Item2.put("id","wh");
		subLevel2Item2.put("value",34445);
		subLevel2Item2.put("unit","m³");
		subLevel2Item2.put("hasChildNodes",true);
		subLevel2Item2.put("fatherNode","dfbt");
		subLevel2Item2.put("isShow",false);
		subLevel2Item2.put("isShowChild",false);
		subLevel2.add(subLevel2Item1);
		subLevel2.add(subLevel2Item2);
//		{title: '车间1', id: 'cj1', value: 12345, unit: 'm³', hasChildNodes: true, fatherNode: 'zz', isShow: false, isShowChild: false},
//		{title: '车间2', id: 'cj2', value: 34445, unit: 'm³', hasChildNodes: true, fatherNode: 'zz', isShow: false, isShowChild: false},
		Map<String, Object> subLevel3Item1 = new HashMap<String,Object>();
		subLevel3Item1.put("title","车间1");
		subLevel3Item1.put("id","cj1");
		subLevel3Item1.put("value",12345);
		subLevel3Item1.put("unit","m³");
		subLevel3Item1.put("hasChildNodes",true);
		subLevel3Item1.put("fatherNode","zz");
		subLevel3Item1.put("isShow",false);
		subLevel3Item1.put("isShowChild",false);
		Map<String, Object> subLevel3Item2 = new HashMap<String,Object>();
		subLevel3Item2.put("title","车间2");
		subLevel3Item2.put("id","cj2");
		subLevel3Item2.put("value",34445);
		subLevel3Item2.put("unit","m³");
		subLevel3Item2.put("hasChildNodes",true);
		subLevel3Item2.put("fatherNode","zz");
		subLevel3Item2.put("isShow",false);
		subLevel3Item2.put("isShowChild",false);
		subLevel3.add(subLevel3Item1);
		subLevel3.add(subLevel3Item2);
//		{title: '线体1', id: 'xt1', value: 12345, unit: 'm³', hasChildNodes: true, fatherNode: 'cj1', isShow: false, isShowChild: false},
//		{title: '线体2', id: 'xt2', value: 34445, unit: 'm³', hasChildNodes: true, fatherNode: 'cj2', isShow: false, isShowChild: false}
		Map<String, Object> subLevel4Item1 = new HashMap<String,Object>();
		subLevel4Item1.put("title","线体1");
		subLevel4Item1.put("id","xt1");
		subLevel4Item1.put("value",12345);
		subLevel4Item1.put("unit","m³");
		subLevel4Item1.put("hasChildNodes",true);
		subLevel4Item1.put("fatherNode","cj1");
		subLevel4Item1.put("isShow",false);
		subLevel4Item1.put("isShowChild",false);
		Map<String, Object> subLevel4Item2 = new HashMap<String,Object>();
		subLevel4Item2.put("title","线体2");
		subLevel4Item2.put("id","xt2");
		subLevel4Item2.put("value",34445);
		subLevel4Item2.put("unit","m³");
		subLevel4Item2.put("hasChildNodes",true);
		subLevel4Item2.put("fatherNode","cj2");
		subLevel4Item2.put("isShow",false);
		subLevel4Item2.put("isShowChild",false);
		subLevel4.add(subLevel4Item1);
		subLevel4.add(subLevel4Item2);
//		{title: '设备1', id: 'sb1', value: 12345, unit: 'm³', hasChildNodes: false, fatherNode: 'xt1', isShow: false, isShowChild: false},
//		{title: '设备2', id: 'sb2', value: 34445, unit: 'm³', hasChildNodes: false, fatherNode: 'xt2', isShow: false, isShowChild: false}
		Map<String, Object> subLevel5Item1 = new HashMap<String,Object>();
		subLevel5Item1.put("title","设备1");
		subLevel5Item1.put("id","sb1");
		subLevel5Item1.put("value",12345);
		subLevel5Item1.put("unit","m³");
		subLevel5Item1.put("hasChildNodes",false);
		subLevel5Item1.put("fatherNode","xt1");
		subLevel5Item1.put("isShow",false);
		subLevel5Item1.put("isShowChild",false);
		Map<String, Object> subLevel5Item2 = new HashMap<String,Object>();
		subLevel5Item2.put("title","设备2");
		subLevel5Item2.put("id","sb2");
		subLevel5Item2.put("value",34445);
		subLevel5Item2.put("unit","m³");
		subLevel5Item2.put("hasChildNodes",false);
		subLevel5Item2.put("fatherNode","xt2");
		subLevel5Item2.put("isShow",false);
		subLevel5Item2.put("isShowChild",false);
		subLevel5.add(subLevel5Item1);
		subLevel5.add(subLevel5Item2);

		result.put("sysData",levelList);

		return result;

	}

	/**
	 * todo delete 临时测试控制 ，直接修改设备状态字段
	 * @return
	 */
	@Transactional(rollbackOn = Exception.class)
	public int updateDeviceStatus(Long devId, String cmd) {

		int status = 0;

		if ("start".equals(cmd)) {
			status = 0;
		} else {
			status = 1;
		}

		String updSql = "update iot_dev_cur_data_win set dvalue = "+ status +" where dev_id =" + devId +" and data_type='运行状态'";
		int resultEffections = em.createNativeQuery(updSql).executeUpdate();

		return resultEffections;
	}

	/**
	 * 加载机房的设备ids
	 * @param spaceId
	 * @return
	 */
	public Map loadStationsIds (Long spaceId) {

		//查询空间节点的子节点
		List<IotSpace> stationsDbResult = iotSpaceRepo.loadStationsObjsByPid(spaceId);
		Map result = new HashMap();

		if (stationsDbResult.size() == 0) {
			return result;
		}

		// 查询空间的子孙空间所挂载的设备
		List<IotDev> spaceDevs = loadSpaceUnderAllConbinedDevices(spaceId);
		if (spaceDevs.size() == 0) {
			return result;
		}
		List<Integer> checkList = Lists.newArrayList();

		for (int i = 0; i < stationsDbResult.size(); i++) {
			IotSpace iotSpace = stationsDbResult.get(i);
			if (iotSpace.getType() == null) {
				continue;
			}
			int index = iotSpace.getType() - 300;

			Optional<IotDev> findOpt = spaceDevs.stream().filter(spa -> spa.getIotSpace().getId().equals(iotSpace.getId())).findFirst();

			findOpt.ifPresent(dev -> {
				result.put(index, dev.getId());
				checkList.add(index);
			});
		}

		for (int i = 0; i < 10; i++) {
			if (!checkList.contains(i)) {
				result.put(i, "");
			}
		}

		return result;

	}

	/**
	 * 加载当前空间的子集空间的 设备ids
	 * @param spaceId
	 * @return
	 */
	public Map loadStationsIdsd (Long spaceId,Integer type) {
		//查询空间节点的子节点
		List<IotSpace> stationsDbResult = iotSpaceRepo.loadSpaceByGrandaByType(spaceId,type);
		Map result = new HashMap();

		if (stationsDbResult.size() == 0) {
			return result;
		}


		Long fatherSpaceid = stationsDbResult.get(0).getId();

		//查询空间节点的子节点
		List<IotSpace> stationsDbResult2 = iotSpaceRepo.loadStationsObjsByPid(fatherSpaceid);
		if (stationsDbResult2.size() == 0) {
			return result;
		}

		// 查询空间的子孙空间所挂载的设备
		List<IotDev> spaceDevs = loadSpaceUnderAllConbinedDevices(fatherSpaceid);

		if (spaceDevs.size() == 0) {
			// 没有挂设备，返回空
			for (int i = 0; i < stationsDbResult.size(); i++) {
				IotSpace curSpace = stationsDbResult.get(i);
				result.put(curSpace.getSort() == null ? "-1" : curSpace.getSort()-1, "");
			}
			return result;
		}

		for (int i = 0; i < stationsDbResult2.size(); i++) {
			IotSpace curSpace = stationsDbResult2.get(i);
			Optional<IotDev> findOpt = spaceDevs.stream().filter(spa -> spa.getIotSpace().getId().equals(curSpace.getId())).findFirst();
			findOpt.ifPresent(dev -> {
				result.put(curSpace.getSort() == null ? "-1" : curSpace.getSort()-1, dev.getId());
			});
			if (!findOpt.isPresent()) {
				result.put(curSpace.getSort() == null ? "-1" : curSpace.getSort()-1, "");
			}
		}

		return result;
	}

    public boolean inspectNumber(String sn, Long id) {
		//设备
		IotDev dev = iotDevRepo.getById(id);
		if (dev != null){
			if (dev.getSn().equals(sn)){
				return false;
			}
		}
		List<IotDev> iotDevs = iotDevRepo.findAll();
		if (iotDevs.size() > 0) {
			for (IotDev iotDev : iotDevs) {
				if (iotDev.getSn().equals(sn)) {
					return true;
				}
			}
		}
		return false;
    }

	public List workshopFirstLevelData(String time, String workSpaceName, String name, String selectType) {
		SqlHelper sqlHelper = SqlHelper.getBySource(this.dataSource);

		Object energySpaceId = iotJsService.getEnergySpaceId(workSpaceName, name);
		if (!ObjectUtils.allNotNull(energySpaceId)){
			return Lists.newArrayList();
		}
		//计算涨幅需要获取上一年的时间
		String lastTime = iotJsService.lastTime(time, UServ.getFormatTimeData(time));

		String sql = "select es1.id, es1.pid, es1.name,SUM(win.dvalue) totalSum, DATE_FORMAT(win.the_time,'%Y') yearIx\n" +
				"from energy_struc_prop esp\n" +
				"inner join energy_struc es1 on esp.energy_struc_id = es1.id\n" +
				"inner join iot_dev_data_win win on esp.dev_id = win.dev_id\n" +
				"inner join energy_struc es2 on es1.pid = es2.id\n" +
				"where\n" +
				"esp.type = 1 and esp.field_type = '用量'\n" +
				"and esp.energy_struc_id = es1.id\n" +
				"and win.data_type = esp.name\n" +
				"and (win.the_time like '"+ time +"%' or win.the_time like '"+ lastTime +"%')\n" +
				"and es1.pid = "+ energySpaceId +"\n" +
				"GROUP BY energy_struc_id, yearIx\n" +
				"union all\n" +
				"select es1.id, es1.pid, es1.name,SUM(win.dvalue) totalSum, DATE_FORMAT(win.the_time,'%Y') yearIx\n" +
				"from energy_struc_prop esp\n" +
				"inner join energy_struc es1 on esp.energy_struc_id = es1.id\n" +
				"inner join iot_dev_data_win win on esp.dev_id = win.dev_id\n" +
				"inner join energy_struc es2 on es1.pid = es2.id\n" +
				"where\n" +
				"esp.type = 1 and esp.field_type = '用量'\n" +
				"and esp.energy_struc_id = es1.id\n" +
				"and win.data_type = esp.name\n" +
				"and (win.the_time like '"+ time +"%' or win.the_time like '"+ lastTime +"%')\n" +
				"and es2.pid = "+ energySpaceId +"\n" +
				"GROUP BY energy_struc_id, yearIx;";
		log.info(sql);
		try {
			List<Map<String,Object>> dbResult = sqlHelper.queryList(sql);
			//计算涨幅
			dbResult = this.calculateGain(dbResult);
			dbResult = this.deleteLastData(dbResult, lastTime);
			//获取能源单位
			String unit = Constant.EnergyUnit.valueOf(name).getValue();
			//组装返回数据
			return this.workshopFirstLevelDataAssemble(dbResult, energySpaceId, unit);
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return Lists.newArrayList();
	}

	/**
	 * 因为要计算涨幅，所以也会查出上一年的数据，需要删除
	 * @param dbResult
	 * @param lastTime
	 * @return
	 */
	private List<Map<String, Object>> deleteLastData(List<Map<String, Object>> dbResult, String lastTime) {
		List<Map<String, Object>> newList = dbResult.stream()
											.filter(map -> !(lastTime.contains(map.get("yearIx").toString())))
											.collect(Collectors.toList());
		return newList;
	}

	private List<Map<String, Object>> calculateGain(List<Map<String, Object>> dbResult) {
		/*List<Map<String, Object>> result = dbResult;
		result.forEach(item1 -> {
			String strGain = "0";//涨幅
			for (Map<String, Object> objectMap : dbResult) {
				//判断相同属性不同时间为计算涨幅
				if (item1.get("name").equals(objectMap.get("name")) && !item1.get("yearIx").equals(objectMap.get("yearIx"))){
					//找出最大时间
					if (Integer.parseInt(item1.get("yearIx").toString()) > Integer.parseInt(objectMap.get("yearIx").toString())){
						Double value1 = Double.parseDouble(item1.get("totalSum").toString());
						Double value2 = Double.parseDouble(objectMap.get("totalSum").toString());
						if (value2 != 0.0) {
							Double gain = (value1 - value2) / value2;
							//获取格式化对象
							NumberFormat nt = NumberFormat.getPercentInstance();
							//设置百分数精确度2即保留两位小数
							nt.setMinimumFractionDigits(2);
							strGain = new DecimalFormat("#.00").format(gain);
//							strGain = nt.format(gain);
						}
					}
				}
			}
			item1.put("increase", strGain);
		});
		return result;*/
		Map<Object, List<Map<String, Object>>> groupingId = dbResult.stream().collect(Collectors.groupingBy((Map map) -> map.get("id")));
		for (Map.Entry<Object, List<Map<String, Object>>> entry : groupingId.entrySet()){
			List<Map<String, Object>> entryValue = entry.getValue();
			//只有size等于2的才需要计算涨幅
			String strGain = "0";//涨幅
			if (CollectionUtils.isNotEmpty(entryValue) && entryValue.size() == 2){
				//计算涨幅
				strGain = specificCalculateGain(entryValue);
			}

			for (Map<String, Object> objectMap : dbResult) {
				if (Objects.equals(objectMap.get("id"), entry.getKey())){
					objectMap.put("increase", strGain);
				}
			}
		}
		return dbResult;
	}

	/**
	 * 计算涨幅
	 * @param entryValue
	 * @return
	 */
	private String specificCalculateGain(List<Map<String, Object>> entryValue) {
		String result = "0";
		Double value1 = Double.parseDouble(entryValue.get(1).get("totalSum").toString());
		Double value2 = Double.parseDouble(entryValue.get(0).get("totalSum").toString());
		if (value2 != 0.0) {
			Double gain = (value1 - value2) / value2;
			//获取格式化对象
			NumberFormat nt = NumberFormat.getPercentInstance();
			//设置百分数精确度2即保留两位小数
			nt.setMinimumFractionDigits(2);
			result = new DecimalFormat("0.00").format(gain);
//			strGain = nt.format(gain);
		}
		return result;
	}

	public List<Map> workshopFirstLevelDataAssemble(List<Map<String, Object>> dbResult, Object energySpaceId, String unit){
		if (CollectionUtils.isNotEmpty(dbResult)){
			List<Map> result = judgeObj(dbResult, energySpaceId, unit);
			return result;
		}
		return Lists.newArrayList();
	}

	//递归组装车间一级数据
	private List<Map> judgeObj(List<Map<String, Object>> dbResult, Object energySpaceId, String unit) {
		List<Map> objects = Lists.newArrayList();
		dbResult.forEach(item -> {
			if (item.get("pid").equals(energySpaceId)){
				Map<String, Object> map = Maps.newHashMap();
				map.put("value", item.get("totalSum"));
				map.put("name", item.get("name"));
				map.put("unit", unit);
				map.put("increase", item.get("increase"));
				List maps = judgeObj(dbResult, item.get("id"), unit);
				map.put("children", maps);
				objects.add(map);
			}
		});
		//objects.sort(Comparator.comparing((Map map) -> map.get("value").toString()).reversed());

		//排序
		Collections.sort(objects, new Comparator<Map>() {
			public int compare(Map o1, Map o2) {
				Double name1 = Double.valueOf(o1.get("value").toString());
				Double name2 = Double.valueOf(o2.get("value").toString());
				return name2.compareTo(name1);
			}
		});
		//排名
		int rank = 1;
		for (Map object : objects) {
			object.put("rank", rank++);
		}
		return objects;
	}

}
